terehinis / jwt-refresh-token-bundle
在Symfony中实现基于Json Web Tokens的刷新令牌系统
Requires
- php: >=5.3.3
- doctrine/doctrine-bundle: ~1.4
- doctrine/orm: ^2.4.8
- lexik/jwt-authentication-bundle: ^1.1|^2.0@dev
- symfony/framework-bundle: ~3.3|~4.0
- symfony/validator: ~3.3|~4.0
Requires (Dev)
- phpspec/phpspec: ^4.0
README
此包的目的是以简单的方式管理JWT(Json Web Tokens)的刷新令牌。此包使用LexikJWTAuthenticationBundle。目前仅支持Doctrine ORM。
先决条件
此包需要Symfony 3.3+或4.0+。
如果您想使用此包与旧版本的Symfony,请使用0.2.x版本。
提示:虽然包没有强制要求这样做,但强烈建议使用HTTPS。
安装
步骤1:下载包
将terehinis/jwt-refresh-token-bundle
添加到您的composer.json
文件中
$ composer require "terehinis/jwt-refresh-token-bundle"
或编辑composer.json
// ...
"terehinis/jwt-refresh-token-bundle": "~0.1",
// ...
步骤2:启用包
然后,通过在您的Symfony应用程序的app/AppKernel.php
文件中添加以下行来启用包
<?php // app/AppKernel.php // ... class AppKernel extends Kernel { public function registerBundles() { $bundles = array( // ... new terehinis\JWTRefreshTokenBundle\terehinisJWTRefreshTokenBundle(), ); } // ... }
步骤3:配置您的刷新令牌路由
打开您的主路由配置文件(通常为app/config/routing.yml
),并将其中的以下四行复制到文件的开始部分。
# app/config/routing.yml terehinis_jwt_refresh_token: path: /api/token/refresh defaults: { _controller: terehinis.jwtrefreshtoken:refresh } # ...
步骤4:允许匿名访问刷新令牌
在security.yml文件中添加以下行
# app/config/security.yml firewalls: refresh: pattern: ^/api/token/refresh stateless: true anonymous: true # ... access_control: # ... - { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY } # ... # ...
步骤5:更新您的模式
使用以下命令创建一个新表来处理您的刷新令牌
php app/console doctrine:schema:update --force
用法
配置TTL
您可以定义刷新令牌的TTL。默认值是1个月。您可以通过在config.yml文件中添加此行来更改此值
terehinis_jwt_refresh_token: ttl: 2592000
配置用户身份字段
您可以更改用户身份字段。请确保您的模型用户有此字段的getter。默认值是username
。您可以通过在config.yml文件中添加此行来更改此值
terehinis_jwt_refresh_token: user_identity_field: email
配置TTL更新
您可以在刷新时扩展刷新令牌的TTL。默认值是false。您可以通过在config.yml文件中添加此行来更改此值
terehinis_jwt_refresh_token: ttl_update: true
这将在每次请求刷新时重置令牌TTL。
配置防火墙名称
您可以定义防火墙名称。默认值是api。您可以通过在config.yml文件中添加此行来更改此值
terehinis_jwt_refresh_token: firewall: api
配置UserProvider
您可以定义自己的UserProvider。默认情况下,我们使用我们的自定义UserProvider。您可以通过在config.yml文件中添加此行来更改此值
terehinis_jwt_refresh_token: user_provider: user_provider_service_id
例如,如果您正在使用FOSUserBundle,则user_provider_service_id必须设置为fos_user.user_provider.username_email
。
使用另一个实体来刷新令牌
您可以定义自己的刷新令牌实体。在您的包中创建扩展terehinis\JWTRefreshTokenBundle\Entity\RefreshToken
的实体类
namespace MyBundle; use terehinis\JWTRefreshTokenBundle\Entity\AbstractRefreshToken; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Doctrine\ORM\Mapping as ORM; /** * This class override terehinis\JWTRefreshTokenBundle\Entity\RefreshToken to have another table name. * * @ORM\Table("jwt_refresh_token") * @ORM\Entity(repositoryClass="terehinis\JWTRefreshTokenBundle\Entity\RefreshTokenRepository") * @UniqueEntity("refreshToken") */ class JwtRefreshToken extends AbstractRefreshToken { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * {@inheritdoc} */ public function getId() { $this->id; } }
然后通过在config.yml文件中添加此行来声明此实体
terehinis_jwt_refresh_token: refresh_token_entity: MyBundle\JwtRefreshToken
使用另一个实体管理器
您可以告诉JWTRefreshTokenBundle使用默认实体管理器(doctrine.orm.entity_manager)之外的另一个实体管理器。
只需在config.yml文件中添加此行即可
terehinis_jwt_refresh_token: entity_manager: my.specific.entity_manager.id
生成令牌
当您通过/api/login_check使用用户/密码凭据进行身份验证时,LexikJWTAuthenticationBundle现在会返回JWT令牌和刷新令牌数据。
{ "token": "eyxxxGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJleHAiOjE0NDI0MDM3NTgsImVtYWlsIjoid2VibWFzdGVyQGdlc2RpbmV0LmNvbSIsImlhdCI6IjE0NDI0MDM3MzgifQ.bo5pre_v0moCXVOZOj-s85gVnBLzdSdsltPn3XrkmJaE8eaBo_zcU2pnjs4dUc9hhwNZK8PL6SmSNcQuTUj4OMK7sUDfXr62a05Ds-UgQP8B2Kpc-ZOmSts_vhgo6xJNCy8Oub9-pRA_78WzUUxt294w0IArrNlgQAGewk65RSMThOif9G6L7HzBM4ajFZ-kMDypz2zVQea1kry-m-XXKNDbERCSHnMeV3rANN48SX645_WEvwaHy0agChR4hTnThzLof2bShA7j7HmnSPpODxQszS5ZBHdMgTvYhlcWJmwYswCWCTPl3lsqVq_UOFI5_4arpSNlUwZsichqxXVAHX5idZqCWtoaqAbvNQe2IpinYajoXw-MlYKvcN2TLUF_8sy529olLUagf4FCpCO6JFxovv0E7ll9tUOVvx9LlannqV8976q5XCOoXszKonZSH7DhsBlW5Emjv7PailbARZ-hfl4YlamyY2QbnxAswYycfoxqJxbbIKYGA8dlebdvMyC7m9VATnasTuKeEKS3mP5iyDgWALBHNYXm1FM-12zHBdN3PbOgxmy_OBGvk05thYFEf2WVmyedtFHy4TGlI0-otUTAf2swQAXWhKtkLWzokWWF7l5iNzam1kkEgql5EOztXHDZpmdKVHWBVNvN3J5ivPjjJBm6sGusf-radcw", "refresh_token": "xxx00a7a9e970f9bbe076e05743e00648908c38366c551a8cdf524ba424fc3e520988f6320a54989bbe85931ffe1bfcc63e33fd8b45d58564039943bfbd8dxxx" }
此刷新令牌持久保存在RefreshToken实体中。之后,当您的JWT有效令牌过期时,如果您想要获取新的令牌,您可以通过两种方式进行
-
再次发送您的用户凭证到/api/login_check。这将生成一个新的JWT和一个新的刷新令牌。
-
使用我们的刷新令牌更新有效的JWT。向/api/token/refresh URL发送带有刷新令牌的有效负载的POST请求。这样,您可以在不要求用户提供用户凭证的情况下始终获取有效的JWT。但是,您必须注意**刷新令牌是否仍然有效**。您的刷新令牌不会改变,但有效日期和时间将增加。
curl -X POST -d refresh_token="xxxx4b54b0076d2fcc5a51a6e60c0fb83b0bc90b47e2c886accb70850795fb311973c9d101fa0111f12eec739db063ec09d7dd79331e3148f5fc6e9cb362xxxx" 'http://xxxx/token/refresh'
此调用返回一个新有效的JWT令牌,更新刷新令牌的有效日期和时间。
有用命令
我们为您提供两个命令来管理令牌。
撤销所有无效令牌
如果您想要撤销所有无效(日期和时间已过期)的刷新令牌,您可以执行以下操作
php app/console terehinis:jwt:clear
可选参数是日期和时间,它将删除小于此日期和时间的所有令牌
php app/console terehinis:jwt:clear 2015-08-08
我们建议使用cronjob定期执行此命令以删除无效的刷新令牌。
撤销令牌
如果您想要撤销单个令牌,可以使用此命令
php app/console terehinis:jwt:revoke TOKEN
事件
如果您想在令牌刷新时执行某些操作,您可以监听terehinis.refresh_token
事件。
例如
<?php namespace AppBundle\EventListener; use terehinis\JWTRefreshTokenBundle\Event\RefreshEvent; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class LogListener implements EventSubscriberInterface { private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function log(RefreshEvent $event) { $refreshToken = $event->getRefreshToken()->getRefreshToken(); $user = $event->getPreAuthenticatedToken()->getUser()->getUsername(); $this->logger->debug(sprintf('User "%s" has refreshed it\'s JWT token with refresh token "%s".', $user, $refreshToken)); } public static function getSubscribedEvents() { return array( 'terehinis.refresh_token' => 'log', ); } }