janakdom/jwt-refresh-token-bundle

在 Symfony 中实现了基于 JSON Web Tokens 的刷新令牌系统

安装: 1,069

依赖: 0

建议者: 0

安全: 0

星星: 0

关注者: 0

分支: 159

类型:symfony-bundle

v0.9.5 2020-10-15 20:54 UTC

README

Scrutinizer Code Quality Build Status Code Coverage Latest Stable Version Total Downloads License StyleCI

此包的目的是以简单的方式管理 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

配置刷新令牌过期

您可以在响应中配置过期参数。如果设置为 true,则将提供令牌过期时间戳。

要启用此行为,请向配置中添加此行

gesdinet_jwt_refresh_token:
    return_expiration: true

配置刷新令牌过期参数名称

您可以定义刷新令牌过期参数名称。默认值是 token_expiration。您可以通过向配置文件中添加此行来更改此值

gesdinet_jwt_refresh_token:
    token_expiration_parameter_name: tokenExpiration

配置 UserProvider

您可以定义自己的 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.ymlconfig/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

您可以定义自己的UserChecker。默认情况下将使用Symfony UserChecker。您可以通过在配置中添加此行来更改此值

gesdinet_jwt_refresh_token:
    user_checker: user_checker_service_id

您可能希望与您的UserChecker一起使用自定义UserProvider,以确保检查器收到正确的用户类型。

配置单次使用

您可以将刷新令牌配置为只能使用一次。如果设置为true并且刷新令牌被使用,将提供新的刷新令牌。

要启用此行为,请向配置中添加此行

gesdinet_jwt_refresh_token:
    single_use: 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\RefreshTokenEvent;
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(RefreshTokenEvent $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',
        );
    }
}