gesdinet / jwt-refresh-token-bundle
在Symfony中实现基于Json Web Tokens的刷新令牌系统
Requires
- php: >=7.4
- doctrine/persistence: ^1.3.3|^2.0|^3.0
- lexik/jwt-authentication-bundle: ^2.0|^3.0
- symfony/config: ^4.4|^5.4|^6.0|^7.0
- symfony/console: ^4.4|^5.4|^6.0|^7.0
- symfony/dependency-injection: ^4.4|^5.4|^6.0|^7.0
- symfony/deprecation-contracts: ^2.1|^3.0
- symfony/event-dispatcher: ^4.4|^5.4|^6.0|^7.0
- symfony/http-foundation: ^4.4|^5.4|^6.0|^7.0
- symfony/http-kernel: ^4.4|^5.4|^6.0|^7.0
- symfony/polyfill-php80: ^1.15
- symfony/property-access: ^4.4|^5.4|^6.0|^7.0
- symfony/security-bundle: ^4.4|^5.4|^6.0|^7.0
- symfony/security-core: ^4.4|^5.4|^6.0|^7.0
- symfony/security-http: ^4.4|^5.4|^6.0|^7.0
Requires (Dev)
- doctrine/annotations: ^1.13|^2.0
- doctrine/cache: ^1.11|^2.0
- doctrine/mongodb-odm: ^2.2
- doctrine/orm: ^2.7
- matthiasnoback/symfony-config-test: ^4.2|^5.0
- matthiasnoback/symfony-dependency-injection-test: ^4.2|^5.0
- phpunit/phpunit: ^9.5
- symfony/cache: ^4.4|^5.4|^6.0|^7.0
- symfony/security-guard: ^4.4|^5.4
Conflicts
- doctrine/mongodb-odm: <2.2
- doctrine/orm: <2.7
- dev-master / 1.x-dev
- v1.3.0
- v1.2.1
- v1.2.0
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.1
- v1.0.0
- v1.0.0-beta4
- v1.0.0-beta3
- v1.0.0-beta2
- v1.0.0-beta
- v0.12.x-dev
- v0.12.0
- v0.11.1
- v0.11
- v0.10.1
- v0.10.0
- 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-analysis-lZjemJ
- dev-analysis-d051Bv
- dev-analysis-9mQAVP
This package is auto-updated.
Last update: 2024-08-30 08:05:56 UTC
README
本扩展包的目的是以简单的方式管理JWT(Json Web Tokens)的刷新令牌。此扩展包使用了LexikJWTAuthenticationBundle。支持Doctrine ORM/ODM。
先决条件
此扩展包需要PHP 7.4或更高版本以及Symfony 4.4、5.4或6.0+。
对于旧版Symfony版本的支持,请使用0.12版本。
技巧:尽管扩展包不会强制您这样做,但强烈建议使用HTTPS。
安装
步骤1:下载扩展包
您还必须安装Doctrine ORM或MongoDB ODM,这些包不会随此扩展包自动安装。未这样做可能会导致安装时出错。
如果使用Symfony 4.4,还需要安装symfony/security-guard
包,它仅适用于旧版认证API,并且与Symfony 6.0不兼容。
使用Doctrine ORM
composer require doctrine/orm doctrine/doctrine-bundle gesdinet/jwt-refresh-token-bundle
使用Doctrine MongoDB ODM
composer require doctrine/mongodb-odm doctrine/mongodb-odm-bundle gesdinet/jwt-refresh-token-bundle
或者,手动编辑项目的composer.json
文件,添加所需的包
{ "require": { "doctrine/doctrine-bundle": "^2.0", "doctrine/mongodb-odm": "^2.0", "doctrine/mongodb-odm-bundle": "^4.0", "doctrine/orm": "^2.7", "gesdinet/jwt-refresh-token-bundle": "^1.0" } }
或者,可以使用自定义持久层。
为此,您必须
- 提供一个
Doctrine\Persistence\ObjectManager
的实现 - 配置扩展包以使用您的对象管理器
步骤2:启用扩展包
Symfony Flex应用程序
对于使用Symfony Flex的应用程序,扩展包应自动注册。如果没有,则需要将其添加到config/bundles.php
文件中。
<?php return [ //... Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle::class => ['all' => true], ];
步骤3:配置扩展包
Symfony Flex应用程序
对于使用Symfony Flex的应用程序,应已应用配方。如果没有,则需要做出以下更改
- 配置刷新令牌类。创建
config/packages/gesdinet_jwt_refresh_token.yaml
文件,内容如下
gesdinet_jwt_refresh_token: refresh_token_class: App\Entity\RefreshToken # This is the class name of the refresh token, you will need to adjust this to match the class your application will use
- 创建对象类。
如果您使用的是Doctrine ORM,则以下内容应放置在src/Entity/RefreshToken.php
(使用注解或属性)
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken as BaseRefreshToken; /** * @ORM\Entity * @ORM\Table("refresh_tokens") */ #[ORM\Entity] #[ORM\Table(name: 'refresh_tokens')] class RefreshToken extends BaseRefreshToken { }
如果您使用的是Doctrine MongoDB ODM,则以下内容应放置在src/Document/RefreshToken.php
(请记住更新上述refresh_token_class
配置以匹配)
<?php namespace App\Document; use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; use Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken as BaseRefreshToken; /** * @ODM\Document(collection="refresh_tokens") */ class RefreshToken extends BaseRefreshToken { }
步骤4(Symfony 5.4+)
定义刷新令牌路由
打开您的路由配置文件,并添加以下路由
# config/routes.yaml api_refresh_token: path: /api/token/refresh # ...
配置认证器
为了启用认证器,您应该将其添加到API防火墙(与json_login
和jwt
认证器一起)。
完整的防火墙配置应类似于以下内容
# config/packages/security.yaml security: # this config is only required on Symfony 5.4, you can leave it out on Symfony 6 enable_authenticator_manager: true firewalls: api: pattern: ^/api stateless: true entry_point: jwt json_login: check_path: /api/login # or, if you have defined a route for your login path, the route name you used success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure jwt: ~ refresh_jwt: check_path: /api/token/refresh # or, you may use the `api_refresh_token` route name # or if you have more than one user provider # provider: user_provider_name # ... access_control: # ... - { path: ^/api/(login|token/refresh), roles: PUBLIC_ACCESS } # ... # ...
步骤4(Symfony 4.4)
定义刷新令牌路由
打开您的路由配置文件,并添加以下路由
# config/routes.yaml api_refresh_token: path: /api/token/refresh controller: gesdinet.jwtrefreshtoken::refresh # ...
配置安全防火墙
将以下内容添加到您的安全配置文件中
# config/packages/security.yaml security: firewalls: # put it before all your other firewall API entries refresh: pattern: ^/api/token/refresh stateless: true anonymous: true # or if you have more than one user provider #provider: user_provider_name # ... access_control: # ... - { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY } # ... # ...
步骤5:更新您的数据库模式
您需要将刷新令牌表添加到应用程序的数据库中。
使用迁移
# If using the MakerBundle:
php bin/console make:migration
# Without the MakerBundle:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
不使用迁移(不建议)
php bin/console doctrine:schema:update --force
用法
以下选项可以通过扩展包的配置在config/packages/gesdinet_jwt_refresh_token.yaml
文件中配置(如果尚未创建,请确保创建它)。
令牌TTL
您可以定义刷新令牌的TTL,此值以秒为单位,默认为1个月。您可以通过添加以下行到配置来更改此值
gesdinet_jwt_refresh_token: ttl: 2592000
更新令牌TTL
您可以通过在配置文件中添加以下行来配置捆绑包,使其在刷新令牌被使用时刷新TTL,默认情况下此功能是禁用的。
gesdinet_jwt_refresh_token: ttl_update: true
配置防火墙名称
注意 此设置已弃用,并且不与 refresh_jwt
认证器一起使用。
您可以定义防火墙名称。默认值是 api
。您可以通过在配置文件中添加以下行来更改此值。
gesdinet_jwt_refresh_token: firewall: api
刷新令牌参数名称
您可以在从请求中读取刷新令牌时定义参数名称,默认值是 refresh_token
。您可以通过在配置文件中添加以下行来更改此值。
gesdinet_jwt_refresh_token: token_parameter_name: refreshToken
返回过期时间戳
如果设置为true,将向响应中添加过期Unix时间戳。
gesdinet_jwt_refresh_token: return_expiration: true
默认参数名称是 refresh_token_expiration
。您可以通过向配置文件中添加以下行来更改参数名称并更改它。
gesdinet_jwt_refresh_token: return_expiration_parameter_name: refresh_token_expiration
设置用户提供者
Symfony 5.4+
您可以为认证器的配置定义一个用户提供者。
注意,如果您的应用程序有多个用户提供者,您 必须 为防火墙或提供者配置此值。
# app/config/security.yml or config/packages/security.yaml security: firewalls: api: pattern: ^/api stateless: true entry_point: jwt json_login: ~ jwt: ~ refresh_jwt: check_path: /api/token/refresh provider: user_provider_service_id
默认情况下,如果没有指定用户提供者,则使用防火墙的用户提供者。
Symfony 4.4
注意 此设置已弃用,并且不与 refresh_jwt
认证器一起使用。
您可以通过默认使用 gesdinet.jwtrefreshtoken.user_provider
服务来定义自己的用户提供者。您可以通过在配置文件中添加以下行来更改此值。
gesdinet_jwt_refresh_token: user_provider: user_provider_service_id
例如,如果您正在使用FOSUserBundle,则必须将 user_provider
设置为 fos_user.user_provider.username_email
。
对于Doctrine ORM UserProvider,必须将 user_provider
设置为 security.user.provider.concrete.<your_user_provider_name_in_security_yaml>
。
例如,在您的 config/packages/security.yaml
文件中
security: # ... providers: app_user_provider: # ... firewalls: # ... # ...
则您的用户提供者服务ID是 security.user.provider.concrete.app_user_provider
。
设置用户检查器
Symfony 5.4+
您可以为防火墙配置定义一个用户检查器。
# app/config/security.yml or config/packages/security.yaml security: firewalls: api_token_refresh: pattern: ^/api/token/refresh stateless: true user_checker: user_checker_service_id refresh_jwt: ~
Symfony 4.4
注意 此设置已弃用,并且不与 refresh_jwt
认证器一起使用。
您可以通过在配置文件中添加以下行来定义自己的用户检查器,默认情况下使用 security.user_checker
服务。您可以通过更改此值来更改它。
gesdinet_jwt_refresh_token: user_checker: user_checker_service_id
您可能想要使用自定义用户提供者以及您的用户检查器,以确保检查器接收正确的用户类型。
单次使用令牌
您可以将刷新令牌配置为只能使用一次。如果设置为 true
且刷新令牌被使用,将提供新的刷新令牌。
要启用此行为,请向配置文件中添加以下行。
gesdinet_jwt_refresh_token: single_use: true
在cookie中设置刷新令牌
默认情况下,刷新令牌返回在JSON响应体中。您可以使用以下配置将其设置在HttpOnly cookie中。刷新令牌在刷新时自动从cookie中提取。
要允许用户在使用cookie时注销,您需要配置 LogoutEvent
在特定路由上触发,并在注销期间调用该路由。
gesdinet_jwt_refresh_token: cookie: enabled: true same_site: lax # default value path: / # default value domain: null # default value http_only: true # default value secure: true # default value partitioned: false # default value remove_token_from_body: true # default value
注销时无效化刷新令牌
此包自动注册一个 EventListener
,该监听器在特定防火墙(默认: api
)的 LogoutEvent
上触发。
LogoutEventListener
自动使指定的刷新令牌无效,如果启用,则取消设置cookie。如果没有提供刷新令牌,则返回错误,并且cookie保持不变。如果提供的刷新令牌(已经)无效,则取消设置cookie。
您只需确保 LogoutEvent
在特定路由上触发,并在注销期间调用该路由即可。
# in security.yaml security: firewalls: api: logout: path: api_token_invalidate
# in routes.yaml api_token_invalidate: path: /api/token/invalidate
如果您想配置LogoutEvent
在另一个防火墙中触发,必须配置该防火墙的名称
# in security.yaml security: firewalls: myfirewall: logout: path: api_token_invalidate
# in routes.yaml api_token_invalidate: path: /api/token/invalidate
# in gesdinet_jwt_refresh_token.yaml gesdinet_jwt_refresh_token: logout_firewall: myfirewall
Doctrine 管理器类型
默认情况下,该捆绑包将尝试使用以下逻辑设置适当的应用程序 Doctrine 对象管理器来定义管理器类型
- 如果
manager_type
配置键设置为“mongodb”,则使用 MongoDB ODM - 如果
manager_type
配置键设置为“orm”(默认),且 ORM 未安装但 MongoDB ODM 已安装,则使用 MongoDB ODM - 默认情况下,
manager_type
为“orm”,并使用 ORM
您可以使用manager_type
配置来自定义管理器类型
gesdinet_jwt_refresh_token: manager_type: mongodb
使用另一个对象管理器
您可以使用object_manager
配置来配置捆绑包使用任何对象管理器。注意,显式定义的object_manager
配置将覆盖基于manager_type
的任何自动配置。
gesdinet_jwt_refresh_token: object_manager: my.specific.entity_manager.id
使用另一个用于刷新令牌的类
您可以通过创建从该捆绑包提供的类扩展的类来为您的项目定义自己的刷新令牌类。这也允许您自定义刷新令牌,例如向令牌添加额外数据。
当使用 Doctrine ORM 时,在您的应用程序中创建一个从Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken
扩展的类
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken; /** * This class extends Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken to have another table name. * * @ORM\Table("jwt_refresh_token") */ class JwtRefreshToken extends RefreshToken { }
当使用 Doctrine MongoDB ODM 时,在您的应用程序中创建一个从Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken
扩展的类
<?php namespace App\Document; use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; use Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken; /** * This class extends Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken to have another collection name. * * @MongoDB\Document(collection="jwt_refresh_token") */ class JwtRefreshToken extends RefreshToken { }
然后声明此类,将以下行添加到您的 config.yml 文件中
gesdinet_jwt_refresh_token: refresh_token_class: App\Entity\JwtRefreshToken
注意:如果使用其他对象管理器,建议您的对象类从Gesdinet\JWTRefreshTokenBundle\Model\AbstractRefreshToken
扩展,该类实现了从Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenInterface
的所有必需方法。
禁用自动 Doctrine 映射
注意:此设置已弃用,不再使用
在某些情况下,您可能不希望启用默认对象管理器的 Doctrine 映射,因为您既不使用 ORM 也不使用 ODM,而是使用 DoctrineBundle 的 DBAL。
要禁用动态 Doctrine 映射,请将此行添加到您的配置中
gesdinet_jwt_refresh_token: doctrine_mappings: false
生成令牌
当您通过/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" }
刷新令牌作为RefreshTokenInterface
对象持久化。之后,当您的 JWT 有效令牌过期时,如果您想要获取一个新的,您可以采取两种方式
- 再次将您的用户凭据发送到/api/login_check。这会生成另一个 JWT 和另一个刷新令牌。
- 使用刷新令牌来更新有效的 JWT。向/api/token/refresh URL 发送 POST 请求,其中刷新令牌作为有效载荷。这样,您始终可以获取有效的 JWT 而不需要请求用户凭据。但是 您必须检查 刷新令牌是否仍然有效。您的刷新令牌不会更改,但其 TTL 会增加。
注意,当刷新令牌被消耗且配置选项single_use
设置为true
时,令牌将不再有效。
curl -X POST -d refresh_token="xxxx4b54b0076d2fcc5a51a6e60c0fb83b0bc90b47e2c886accb70850795fb311973c9d101fa0111f12eec739db063ec09d7dd79331e3148f5fc6e9cb362xxxx" 'http://xxxx/token/refresh'
此调用返回一个新的有效 JWT 令牌,更新刷新令牌的有效日期。
有用的命令
吊销所有无效令牌
如果您想吊销所有无效(日期已过期)的刷新令牌,您可以执行
php bin/console gesdinet:jwt:clear
该命令可选地接受一个日期参数,将删除所有给定时间之前的老令牌。这可以是任何可以由DateTime
类解析的值。
php bin/console gesdinet:jwt:clear 2015-08-08
我们建议将此命令作为 cronjob 执行,以定期删除无效的刷新令牌。
吊销令牌
如果您想吊销单个令牌,您可以使用此命令
php bin/console gesdinet:jwt:revoke TOKEN
事件
令牌已刷新
当令牌被刷新时,将使用gesdinet.refresh_token
事件发布一个Gesdinet\JWTRefreshTokenBundle\Event\RefreshEvent
对象。
刷新令牌失败
注意 此事件仅在使用与Symfony 5.4+一起使用的refresh_jwt
验证器时可用。
当验证刷新令牌失败时,将使用Gesdinet\JWTRefreshTokenBundle\Event\RefreshAuthenticationFailureEvent
对象触发gesdinet.refresh_token_failure
事件。
未找到刷新令牌
注意 此事件仅在使用与Symfony 5.4+一起使用的refresh_jwt
验证器时可用。
当验证刷新令牌失败时,将使用Gesdinet\JWTRefreshTokenBundle\Event\RefreshTokenNotFoundEvent
对象触发gesdinet.refresh_token_not_found
事件。
令牌提取器
该组件提供Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface
以定义可以从请求中读取刷新令牌的类。
默认情况下,使用Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ChainExtractor
,这允许检查请求的多个方面以获取令牌。找到的第一个令牌将被使用。
您可以通过向应用程序中添加实现该接口的类来创建自定义提取器。例如,要添加一个检查“X-Refresh-Token”头部的提取器
<?php namespace App\Request\Extractor; use Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface; use Symfony\Component\HttpFoundation\Request; final class HeaderExtractor implements ExtractorInterface { public function getRefreshToken(Request $request, string $parameter): ?string { return $request->headers->get('X-Refresh-Token'); } }
此组件会自动配置ExtractorInterface
对象,并在您的应用程序使用自动配置(在services.yaml
文件中设置autoconfigure: true
)时自动设置gesdinet_jwt_refresh_token.request_extractor
容器标签。如果不使用自动配置,您需要手动配置此标签
services: App\Request\Extractor\HeaderExtractor: tags: - { name: gesdinet_jwt_refresh_token.request_extractor }
提取器的优先级
gesdinet_jwt_refresh_token.request_extractor
容器标签支持提取器的优先级,您可以通过添加一个priority
属性来设置提取器的首选顺序。数字越高,提取器运行的越早。
services: App\Request\Extractor\HeaderExtractor: tags: - { name: gesdinet_jwt_refresh_token.request_extractor, priority: 25 }