innobyte / token-bundle
A Symfony2 Bundle实现基于访问的令牌系统,具有生成、验证和消费机制。
2.1.2
2022-01-17 11:36 UTC
Requires
- php: >=5.5.0
- doctrine/doctrine-bundle: ~1.4 | ~2.0
- symfony/config: ~2.3|~3.0|~4.0|~5.0
- symfony/dependency-injection: ~2.3|~3.0|~4.0|~5.0
- symfony/http-kernel: ~2.3|~3.0|~4.0|~5.0
README
TokenBundle的目标是提供一种验证用户采取的措施的方法。
通过使用散列来实现验证,例如,可以嵌入在URL中,无论是电子邮件还是页面内生成的即时链接。
安装
composer.json - 安装捆绑包
"require": {
"innobyte/token-bundle": "~1.1",
},
AppKernel.php - 注册捆绑包
在$bundles
数组中添加以下行
new Innobyte\TokenBundle\InnobyteTokenBundle(),
config.yml - 添加捆绑映射
在实体管理器(此处为"local")下添加捆绑的映射。注意:"default"是实体管理器的默认名称,如果没有指定其他名称。
doctrine:
...
orm:
...
entity_managers:
local:
...
mappings:
...
InnobyteTokenBundle: ~
parameters.yml - 添加实体管理器名称
添加实体管理器名称(此处为"local")- 在上一步中放入映射的那个。如果没有提供,将使用"default"。注意:只有当实体管理器名称不是"default"时才必须指定。否则,可以完全省略此步骤。
innobyte_token:
entity_manager: local
更新模式
首先,运行app/console doctrine:schema:update --em=default --dump-sql
来查看生成的SQL。
然后,运行app/console doctrine:schema:update --em=default --force
在数据库上运行查询。
使用方法
生成令牌
$token = $this->get('innobyte_token')->generate(
'scope',
'owner_type',
123, // owner_id
1, // number of uses - optional
new \DateTime('+1 day'), // expiry time - optional
array('author' => 'admin') // additional data to check against - optional
);
// use hash (embed in a link/email etc.)
$hash = $token->getHash();
验证令牌并消费它
try {
$this->get('innobyte_token')->consume(
'19debf971fb937853d77fca8fd3bb775',
'scope',
'owner_type',
123 // owner_id
);
} catch (\Innobyte\TokenBundle\Exception\TokenNotFoundException $e) {
echo 'cannot find Token';
} catch (\Innobyte\TokenBundle\Exception\TokenInactiveException $e) {
echo 'handle explicit disabled token here';
} catch (\Innobyte\TokenBundle\Exception\TokenConsumedException $e) {
echo 'handle over-used token here';
} catch (\Innobyte\TokenBundle\Exception\TokenExpiredException $e) {
echo 'handle expired token here';
} catch (\Innobyte\TokenBundle\Exception\TokenException $e) {
// or, alternately, you can catch all token-related exceptions
echo 'handle all token-related exceptions';
}
echo 'Token is valid. Token is valid. Perform logic here.';
获取令牌并手动验证和消费它
$token = $this->get('innobyte_token')->get(
'5c15e262c692dbaac75451dcb28282ab',
'scope',
'owner_type',
123 // owner_id
);
// if wrong link or disabled/overused token
if (!$this->get('innobyte_token')->isValid($token)) {
echo 'Handle invalid token here';
}
// or even more explicit
if (!$token instanceof \Innobyte\TokenBundle\Entity\Token) {
echo 'handle invalid token here';
} else {
// manually mark the usage
try {
$this->get('innobyte_token')->consumeToken($token);
} catch (\LogicException $e) {
echo 'cannot consumed Token because it is not managed';
}
echo 'Token is valid. Perform logic here.';
}
无效化
对于无效化,有与"消费"类似的方法:"invalidate"(禁用令牌)
try {
$this->get('innobyte_token')->invalidate(
'5c15e262c692dbaac75451dcb28282ab',
'scope',
'owner_type',
123 // owner_id
);
} catch (\Innobyte\TokenBundle\Exception\TokenNotFoundException $e) {
echo 'Handle Token not found here';
}
if (!$token instanceof \Innobyte\TokenBundle\Entity\Token) {
echo 'Handle invalid token here';
} else {
try {
$this->get('innobyte_token')->invalidateToken($token);
} catch (\LogicException $e) {
echo 'Cannot consume Token because it is not managed';
}
}
高级验证
在执行标准Token验证后,可以使用其他数据来验证其他条件。
// first, generate the Token
$token = $this->get('innobyte_token')->generate(
'scope',
'owner_type',
123, // owner_id
1, // number of uses - optional
new \DateTime('+1 hour'), // expiry time - optional
array('ip' => $request->getClientIp()) // additional data to check against - optional
);
// use hash (embed in a link/email etc.)
$hash = $token->getHash();
// then, validate it
$token = $this->get('innobyte_token')->get(
$hash,
'scope',
'owner_type',
123 // owner_id
);
// if wrong link or disabled/overused token
if (!$this->get('innobyte_token')->isValid($token)) {
echo 'Handle invalid token here';
}
// additional validation by IP
$additionalData = $token->getData();
if ($additionalData['ip'] != $request->getClientIp()) {
echo 'Handle invalid token here';
}
单元测试
不要忘记在config_test.yml
中将数据库凭据覆盖为测试数据库的凭据。示例
parameters:
database_host: 127.0.0.1
database_port: null
database_name: test_db
database_user: root
database_password: 123
要运行测试,执行
phpunit -c app/ vendor/innobyte/token-bundle/Innobyte/TokenBundle/Tests/