teresko / palladium
用户认证和注册组件
Requires
- php: >=7.0
- ext-pdo: *
- psr/log: 1.*
Requires (Dev)
- ext-pdo_sqlite: *
- phpunit/phpunit: ^6.1
README
(工作进度:2.0版本文档)
用于处理用户身份识别的库。
该库的目的是定位给定身份证明的用户账户(确切地说,是其唯一ID),并管理各种类型的身份。它由4个不同的服务组成:识别、注册、搜索和恢复。
安装
您可以使用以下命令使用composer将库添加到您的项目中
composer require teresko/palladium
使用此包需要PHP版本7.0+和PDO。
您还需要创建一个表,用于存储标识信息。示例模式可在此处找到。它目前仅包含MySQL/MariaDB的表定义,但该库可以与任何具有PDO驱动的RDBMS一起使用。
初始化
Palladium包含4个服务:Registration
、Identification
、Search
和Recovery
。这些服务中的每一个都有两个强制依赖项
- 仓库(实现
Palladium\Contract\CanPersistIdenity
) - 日志记录器(实现
Psr\Log\LoggerInterface
)
这为您提供了替换默认仓库的选项,如果您想更改或替换持久化抽象层的一部分。至于日志记录器,建议使用Monolog,但与任何兼容的日志系统都应能正常工作。
默认仓库还包含添加自定义身份类型和数据映射器的功能,这些映射器用于您或内置的身份类型。有关使用详情,请参阅%TODO%部分。
可选参数
在Identification
服务的构造函数中,有一个可选的第三和第四参数
- cookie的生命周期(以秒为单位),默认为4小时。
- hash成本(用于BCrypt),默认为12
在Registration
服务的构造函数中,有一个可选的第三参数
- hash成本(用于BCrypt),默认为12
设置仓库
如上所述,所有4个服务都期望一个仓库作为构造函数依赖项。如果您不替换捆绑的仓库以使用自定义版本,那么您需要初始化Palladium\Repository\Identity
并将其传递给服务。
捆绑的仓库本身只有一个依赖项:实现Palladium\Contract\CanCreateMapper
的实例。该契约(接口)由Palladium\Component\MapperFactory
实现。此工厂有两个依赖项:PDO
实例和存储标识信息的表名。
<?php $factory = new \Palladium\Component\MapperFactory(new \PDO(...$config), $tableName); $repository = new \Palladium\Repository\Identity($factory);
在所有其他代码示例中,如果您看到使用$repository
变量的地方,您可以假设它已经使用此代码示例进行了初始化。
与DI容器一起使用
对于使用Symfony的DependencyInjection Component(版本:3.4+)的用户,有一个示例配置文件:%TODO%
用法
注册新的身份
<?php $registration = new \Palladium\Service\Registration($repository, $logger); $identity = $registration->createStandardIdentity('foo@bar.com', 'password'); $registration->bindAccountToIdentity($accountId, $identity);
如果操作成功完成,变量$identity
将包含一个未经验证的StandardIdentity
实例。[StandardIdentity
](https://github.com/teresko/palladium/blob/master/src/Palladium/Entity/StandardIdentity.php)。要完成验证,您必须使用身份中包含的令牌。在给出的示例中,此令牌可以通过$instance->getToken()
来获取。
如果电子邮件已被用于另一个身份,则createStandardIdentity()
方法可能会抛出IdentityConflict
异常。
createStandardIdentity()
方法有一个可选的第三个参数,它定义了电子邮件验证令牌的持续时间(以秒为单位)。应用后,前面的示例如下所示:
<?php $registration = new \Palladium\Service\Registration($repository, $logger); $identity = $registration->createStandardIdentity('foo@bar.com', 'password', 3600); $registration->bindAccountToIdentity($accountId, $identity);
这将使验证令牌在用户身份注册后的1小时内可用。在此给定时间过后,您将无法使用findStandardIdentityByToken()
在Search
服务中找到此身份。
重要:
createStandardIdentity()
方法不验证用户的电子邮件或其他类型的标识符。它只检查其唯一性。电子邮件、电话号码、昵称和其他标识符的验证超出了此库的范围。
身份验证
<?php $search = new \Palladium\Service\Search($repository, $logger); $registration = new \Palladium\Service\Registration($repository, $logger); $identity = $search->findStandardIdentityByToken($token, \Palladium\Entity\Identity::ACTION_VERIFY); $registration->verifyStandardIdentity($identity);
使用$token
值定位匹配的EmailIdentity
,然后进行验证。如果找不到身份,则findStandardIdentityByToken()
将抛出IdentityNotFound
异常。
使用电子邮件和密码登录
<?php $search = new \Palladium\Service\Search($repository, $logger); $identification = new \Palladium\Service\Identification($repository, $logger); $identity = $search->findStandardIdentityByIdentifier($identifier); $cookie = $identification->loginWithPassword($identity, $password);
如果没有找到与给定标识符(例如,电子邮件地址)匹配的身份,则findStandardIdentityByIdentifier()
方法将抛出IdentityNotFound
异常。
如果密码不匹配,则loginWithPassword()
方法将抛出PasswordMismatch
异常。
创建新的单次使用登录
<?php $identity = $this->registration->createNonceIdentity($accountId);
这将创建一个新的NonceIdentity
实例。要使用它进行登录,您需要使用NonceIdentity::getIdentifier()
和NonceIdentity::getKey()
中的值,其中标识符将用于定位一次性身份,而密钥将用于验证。
当应用时,createNonceIdentity()
方法有一个可选的第二个参数,它定义了此一次性身份的持续时间(以秒为单位)。应用后的示例如下所示:
<?php $identity = $this->registration->createNonceIdentity($accountId, 600);
这将使一次性身份在其创建后的10分钟内可用。在此允许的时间过后,将此身份传递到Identification
的useNonceIdentity()
方法中将导致抛出IdentityExpired
异常。
使用一次性令牌登录
<?php $identity = $this->search->findNonceIdentityByIdentifier($identifier); $cookie = $this->identification->useNonceIdentity($identity, $key);
如果没有找到与给定标识符(电子邮件地址、昵称等)匹配的身份,则findNonceIdentityByIdentifier()
方法将抛出IdentityNotFound
异常。
如果密码不匹配,则useNonceIdentity()
方法将抛出KeyMismatch
异常。
使用cookie登录
<?php $search = new \Palladium\Service\Search($repository, $logger); $identification = new \Palladium\Service\Identification($repository, $logger); $identity = $search->findCookieIdentity($accountId, $series); $cookie = $identification->loginWithCookie($identity, $key);
如果使用findCookieIdentity()
找不到cookie,将会抛出一个标准的IdentityNotFound
异常。导致这种情况的可能原因包括cookie已不再活跃(例如,用户注销)或cookie根本不存在。
如果cookie太旧,loginWithCookie()
将产生IdentityExpired
异常。
但是,loginWithCookie()
方法也可能产生CompromisedCookie
异常。出现此类异常可能表明cookie已被盗用,或者用户从未收到新的cookie值。
阻止受损的cookie
<?php $search = new \Palladium\Service\Search($repository, $logger); $identification = new \Palladium\Service\Identification($repository, $logger); $identity = $search->findCookieIdentity($accountId, $series); $identification->blockIdentity($identity);
这是处理可疑cookie(可能已遭盗用)的推荐方法。这并非用于注销用户。
注销
<?php $search = new \Palladium\Service\Search($repository, $logger); $identification = new \Palladium\Service\Identification($repository, $logger); $identity = $search->findCookieIdentity($accountId, $series); $identification->logout($identity, $key);
此操作将cookie标记为“已丢弃”。可以产生的异常列表与使用cookie登录部分中描述的相同。
启动密码重置过程
<?php $search = new \Palladium\Service\Search($repository, $logger); $recovery = new \Palladium\Service\Recovery($repository, $logger); $identity = $search->findStandardIdentityByIdentifier($identifier); $token = $recovery->markForReset($identity);
如果找不到与给定电子邮件地址匹配的标识符,findStandardIdentityByIdentifier()
方法将抛出IdentityNotFound
异常。
当调用markForReset()
时,必须提供已验证的StandardIdentity
实例(否则,可能会导致您的应用程序泄露用户的私人信息)。如果不是这种情况,该方法将抛出IdentityNotVerified
异常。
markForReset()
方法有一个可选的第二个参数,它定义了密码重置令牌的有效期(以秒为单位)。应用后,前面的示例如下所示
<?php $search = new \Palladium\Service\Search($repository, $logger); $recovery = new \Palladium\Service\Recovery($repository, $logger); $identity = $search->findStandardIdentityByIdentifier($identifier); $token = $recovery->markForReset($identity, 7200);
这将使密码重置令牌在用户标识被标记为重置后的两小时内可用。当允许的时间过期后,您将无法在Search
服务中使用findEmailIdentityByToken()
找到此标识。
密码重置完成
<?php $search = new \Palladium\Service\Search($repository, $logger); $recovery = new \Palladium\Service\Recovery($repository, $logger); $identity = $search->findEmailIdentityByToken($token, \Palladium\Entity\Identity::ACTION_RESET); $recovery->resetIdentityPassword($identity, 'foobar');
如果找不到与给定令牌匹配的标识符,findEmailIdentityByToken()
方法将抛出IdentityNotFound
异常。
更改电子邮件身份的密码
<?php $search = new \Palladium\Service\Search($repository, $logger); $identification = new \Palladium\Service\Identification($repository, $logger); $identity = $search->findStandardIdentityByIdentifier($identifier); $identification->changePassword($identity, $oldPassword, $newPassword);
如果找不到与给定电子邮件地址(或任何其他类型的标识符)匹配的标识符,findStandardIdentityByIdentifier()
方法将抛出IdentityNotFound
异常。
如果密码不匹配,changePassword()
方法将抛出PasswordMismatch
异常。
批量注销身份
<?php $search = new \Palladium\Service\Search($repository, $logger); $identification = new \Palladium\Service\Identification($factory, $logger); $list = $search->findIdentitiesByParentId($identity->getId()); $identification->discardIdentityCollection($list);
findIdentitiesByParentId()
的返回值将返回一个可能为空的IdentityCollection
。
记录用户活动
如前所述,此库中的服务期望一个PSR-3兼容的日志记录器作为依赖项。它将用于记录三个级别的事件
LogLevel::INFO
此日志级别用于跟踪用户在使用应用程序时按预期执行的操作
- 成功注册
- 成功恢复密码
- 成功登录(使用电子邮件/用户名或cookie)或注销
- 成功验证电子邮件
- 使用过期的cookie或nonce
LogLevel::NOTICE
当用户尝试了不应在正确使用场景中发生的失败操作时,将记录此级别的日志。
- 所有身份未找到的情况
- 输入了错误的密码
- 标识符已被用于不同的身份
- 尝试使用未经验证的邮箱恢复密码
LogLevel::WARNING
仅用于记录用户尝试使用受损cookie的情况。
附加说明
此库专注于一项特定任务。它不包含以下任何功能:
- 账户创建和管理
- 授权系统
- 用户输入验证(包括电子邮件和密码)
- 日志框架
如果您认为身份验证库需要上述列出的任何部分,那么这并非您要寻找的库。