free-work-agsi / jwt-refresh-token-bundle
在 Symfony 中实现基于 Json Web Tokens 的刷新令牌系统
Requires
- php: ^5.5.9|>=7.0.8
- lexik/jwt-authentication-bundle: ^1.1|^2.0@dev
- symfony/framework-bundle: ~3.4|~4.0|~5.0
- symfony/validator: ~3.4|~4.0|~5.0
Requires (Dev)
- doctrine/doctrine-bundle: ~1.4|~2.0
- doctrine/mongodb-odm-bundle: ^3.4|^4.0
- doctrine/orm: ^2.4.8
- phpspec/phpspec: ^3.0|^4.0|^5.0|^6.0
- dev-master / 1.0.x-dev
- v0.9.6
- v0.9.5
- v0.9.4
- v0.9.3
- v0.9.2
- v0.9.1
- v0.9.0
- v0.8.3
- v0.8.2
- v0.8.1
- v0.7.1
- v0.7.0
- v0.6.2
- v0.6.1
- v0.6.0
- v0.5.4
- v0.5.3
- v0.5.2
- v0.5.1
- v0.5.0
- v0.4.0
- v0.3.3
- v0.3.2
- v0.3.1
- v0.3.0
- v0.2.1
- v0.2.0
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1
- dev-feature-cookie-support
- dev-analysis-1bdnMy
- dev-markitosgv-patch-2
- dev-analysis-XpnJDW
- dev-markitosgv-patch-1
This package is auto-updated.
Last update: 2024-08-24 19:48:18 UTC
README
此包的目的是以简单的方式管理 JWT (Json Web Tokens) 的刷新令牌。此包使用 LexikJWTAuthenticationBundle。支持 Doctrine ORM/ODM。
先决条件
此包需要 Symfony 3.4+、4.0+ 或 5.0+。
如果您想使用此包与之前的 Symfony 版本,请使用 0.2.x 版本。
技巧:尽管此包没有强制要求您这样做,但强烈建议使用 HTTPS。
安装
步骤 1: 下载包
手动要求 Doctrine 的 ORM 或 MongoDB ODM 也非常重要,因为这些包现在不是自动要求的,您可以选择它们之间。未这样做可能会导致安装时出错
使用 Doctrine 的 ORM
$ composer require "doctrine/orm" "doctrine/doctrine-bundle" "gesdinet/jwt-refresh-token-bundle"
使用 Doctrine 的 MongoDB ODM
$ composer require "doctrine/mongodb-odm-bundle" "gesdinet/jwt-refresh-token-bundle"
或编辑 composer.json
// ...
"gesdinet/jwt-refresh-token-bundle": "~0.1",
"doctrine/orm": "^2.4.8",
"doctrine/doctrine-bundle": "~1.4",
"doctrine/mongodb-odm-bundle": "^3.4"
// ...
步骤 2: 启用包
Symfony 3 版本
将包注册到 app/AppKernel.php
<?php // app/AppKernel.php // ... class AppKernel extends Kernel { public function registerBundles() { $bundles = array( // ... new Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle(), ); } // ... }
Symfony 4 版本
将包注册到 config/bundles.php
(Flex 会自动完成)
return [ //... Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle::class => ['all' => true], ];
步骤 3: 配置刷新令牌的自己的路由
打开您的主要路由配置文件,并将其以下四行复制到文件的开头。
Symfony 3 版本
# app/config/routing.yml gesdinet_jwt_refresh_token: path: /api/token/refresh defaults: { _controller: gesdinet.jwtrefreshtoken:refresh } # ...
Symfony 4 版本
# config/routes.yml gesdinet_jwt_refresh_token: path: /api/token/refresh controller: gesdinet.jwtrefreshtoken::refresh # ...
步骤 4: 允许匿名访问刷新令牌
在 security.yml 文件中添加以下行
# app/config/security.yml or config/packages/security.yaml firewalls: # put it before all your other firewall API entries refresh: pattern: ^/api/token/refresh stateless: true anonymous: true # ... access_control: # ... - { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY } # ... # ...
步骤 5: 更新您的模式
使用以下命令,您将创建一个新表来处理您的刷新令牌
Symfony 3 版本
php bin/console doctrine:schema:update --force
# or make and run a migration
php bin/console make:migration
php bin/console doctrine:migrations:migrate
Symfony 4 版本
php bin/console doctrine:schema:update --force
# or make and run a migration:
php bin/console make:migration
php bin/console doctrine:migrations:migrate
用法
配置可以放在
Symfony 3 版本: app/config
Symfony 4 版本: config/packages/gesdinet_jwt_refresh_token.yaml
配置 TTL
您可以为刷新令牌定义 TTL。默认值是 1 个月。您可以通过添加此行到您的配置来更改此值
gesdinet_jwt_refresh_token: ttl: 2592000
配置用户身份字段
您可以更改用户身份字段。确保您的模型用户有此字段的 getter
。默认值是 username
。您可以通过添加此行到您的配置来更改此值
gesdinet_jwt_refresh_token: user_identity_field: email
配置 TTL 更新
您可以在刷新时扩展刷新令牌的 TTL。默认值是 false。您可以通过添加此行到您的配置来更改此值
gesdinet_jwt_refresh_token: ttl_update: true
这将每次您请求刷新时重置令牌 TTL。
配置防火墙名称
您可以定义防火墙名称。默认值是 api。您可以通过添加此行到您的配置来更改此值
gesdinet_jwt_refresh_token: firewall: api
配置刷新令牌参数名称
您可以定义刷新令牌参数名称。默认值是 refresh_token。您可以通过添加此行到您的配置文件来更改此值
gesdinet_jwt_refresh_token: token_parameter_name: refreshToken
配置用户提供者
您可以定义您自己的 UserProvider。默认情况下,我们使用我们自己的 UserProvider。您可以通过添加此行到您的配置来更改此值
gesdinet_jwt_refresh_token: user_provider: user_provider_service_id
例如,如果您正在使用 FOSUserBundle,则 user_provider_service_id 必须设置为 fos_user.user_provider.username_email
。
对于 Doctrine ORM UserProvider,user_provider_service_id 必须设置为 security.user.provider.concrete.<your_user_provider_name_in_security_yaml>
。例如,在您的 app/config/security.yml
或 config/packages/security.yaml
security: # ... providers: app_user_provider: # ... firewalls: # ... # ...
则您的 user_provider_service_id 是 security.user.provider.concrete.app_user_provider
。
选择管理器类型
默认情况下,管理器类型设置为使用 Doctrine 的 ORM,如果您想使用 Doctrine 的 MongoDB ODM,则必须更改此值
gesdinet_jwt_refresh_token: manager_type: mongodb
配置用户检查器
您可以定义自己的UserChecker。默认情况下,将使用Symfony UserChecker。您可以通过在配置中添加以下行来更改此值:
gesdinet_jwt_refresh_token: user_checker: user_checker_service_id
您可能希望与自定义UserChecker一起使用自定义UserProvider,以确保检查器接收到正确的用户类型。
配置单次使用
您可以将刷新令牌配置为只能使用一次。如果设置为true
并且刷新令牌被消耗,将提供新的刷新令牌。
要启用此行为,请将此行添加到您的配置中
gesdinet_jwt_refresh_token: single_use: true
在cookie中配置刷新令牌
默认情况下,刷新令牌作为JSON响应返回。您可以配置以通过cookie检索它。然后cookie将自动从请求中提取。
以下是默认值。
gesdinet_jwt_refresh_token: cookie: sameSite: lax path: / domain: null httpOnly: true secure: true
使用其他实体刷新令牌
您可以在项目中定义自己的刷新令牌类。
当使用默认ORM时,在您的包中创建扩展Gesdinet\JWTRefreshTokenBundle\Entity\AbstractRefreshToken
的实体类。
namespace MyBundle; use Doctrine\ORM\Mapping as ORM; use Gesdinet\JWTRefreshTokenBundle\Entity\AbstractRefreshToken; /** * This class override Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken to have another table name. * * @ORM\Table("jwt_refresh_token") */ class JwtRefreshToken extends AbstractRefreshToken { /** * @var int * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * {@inheritdoc} */ public function getId() { return $this->id; } }
当使用MongoBD ODM时,在您的包中创建扩展Gesdinet\JWTRefreshTokenBundle\Document\AbstractRefreshToken
的文档类。
namespace MyBundle; use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; use Gesdinet\JWTRefreshTokenBundle\Document\AbstractRefreshToken; /** * This class override Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken to have another collection name. * * @MongoDB\Document(collection="UserRefreshToken") */ class JwtRefreshToken extends AbstractRefreshToken { /** * @var string * * @MongoDB\Id(strategy="auto") */ protected $id; /** * {@inheritdoc} */ public function getId() { return $this->id; } }
然后通过在config.yml文件中添加此行来声明此类
gesdinet_jwt_refresh_token: refresh_token_class: MyBundle\JwtRefreshToken
使用其他对象管理器
您可以让JWTRefreshTokenBundle使用默认对象管理器之外的另一个对象管理器(如果使用ORM,则为doctrine.orm.entity_manager;如果使用MongoDB ODM,则为doctrine_mongodb.odm.document_manager)。
只需将此行添加到您的config.yml文件中
gesdinet_jwt_refresh_token: object_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而无需请求用户凭据。但请注意刷新令牌是否仍然有效。您的刷新令牌不会更改,但有效日期将增加。
请注意,当刷新令牌被消耗并且配置选项single_use
设置为true
时,令牌将不再有效。
curl -X POST -d refresh_token="xxxx4b54b0076d2fcc5a51a6e60c0fb83b0bc90b47e2c886accb70850795fb311973c9d101fa0111f12eec739db063ec09d7dd79331e3148f5fc6e9cb362xxxx" 'http://xxxx/token/refresh'
此调用返回新的有效JWT令牌,并更新刷新令牌的有效日期。
有用的命令
我们为您提供两个命令来管理令牌。
吊销所有无效令牌
如果您想吊销所有无效(日期过期)的刷新令牌,可以执行以下操作
Symfony 3 版本
php bin/console gesdinet:jwt:clear
Symfony 4 版本
php bin/console gesdinet:jwt:clear
可选参数是日期时间,它删除所有小于此日期时间的令牌
Symfony 3 版本
php bin/console gesdinet:jwt:clear 2015-08-08
Symfony 4 版本
php bin/console gesdinet:jwt:clear 2015-08-08
我们建议使用cronjob定期执行此命令以删除无效的刷新令牌。
吊销令牌
如果您想吊销单个令牌,可以使用此命令
Symfony 3 版本
php bin/console gesdinet:jwt:revoke TOKEN
Symfony 4 版本
php bin/console gesdinet:jwt:revoke TOKEN
事件
如果您想在令牌刷新时执行某些操作,可以监听gesdinet.refresh_token
事件。
例如
<?php namespace AppBundle\EventListener; use Gesdinet\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( 'gesdinet.refresh_token' => 'log', ); } }