Yii2 JWT

这个扩展为Yii framework 2.0提供了JWT集成(需要PHP 5.6+)。它包括基本的HTTP身份验证支持。

目录

  1. 安装
  2. 依赖关系
  3. 基本用法
    1. 创建
    2. 从字符串分析
    3. 验证
  4. 令牌签名
    1. Hmac
    2. RSA和ECDSA
  5. Yii2基本模板示例

安装

Package is available on Packagist,

you can install it using Composer.

composer require sizeg/yii2-jwt

依赖关系

基本用法

jwt 组件添加到配置文件中,

'components' => [
'jwt' => [
'class' => \sizeg\jwt\Jwt::class,
'key' => 'secret',
],
],

按如下方式配置 authenticator 行为。

namespace app\controllers;

class ExampleController extends \yii\rest\Controller
{ /**
* @inheritdoc
*/
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => \sizeg\jwt\JwtHttpBearerAuth::class,
]; return $behaviors;
}
}

也可以将其与 CompositeAuth 参考文献 一起用于文档

创建

有些方法被标记为已弃用,并很快将从lcobucci/jwt 4.x回传内容以创建升级路径。

只需使用构建器创建一个新的JWT/JWS令牌:

$time = time();
$token = Yii::$app->jwt->getBuilder()
->issuedBy('http://example.com') // Configures the issuer (iss claim)
->permittedFor('http://example.org') // Configures the audience (aud claim)
->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
->issuedAt($time) // Configures the time that the token was issue (iat claim)
->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
->withClaim('uid', 1) // Configures a new claim, called "uid"
->getToken(); // Retrieves the generated token $token->getHeaders(); // Retrieves the token headers
$token->getClaims(); // Retrieves the token claims echo $token->getHeader('jti'); // will print "4f1g23a12aa"
echo $token->getClaim('iss'); // will print "http://example.com"
echo $token->getClaim('uid'); // will print "1"
echo $token; // The string representation of the object is a JWT string (pretty easy, right?)

从字符串分析

使用解析器从JWT字符串创建一个新的令牌(以前面的令牌为例):

$token = Yii::$app->jwt->getParser()->parse((string) $token); // Parses from a string
$token->getHeaders(); // Retrieves the token header
$token->getClaims(); // Retrieves the token claims echo $token->getHeader('jti'); // will print "4f1g23a12aa"
echo $token->getClaim('iss'); // will print "http://example.com"
echo $token->getClaim('uid'); // will print "1"

验证

我们可以很容易地验证令牌是否有效(以前面的令牌为例):

$data = Yii::$app->jwt->getValidationData(); // It will use the current time to validate (iat, nbf and exp)
$data->setIssuer('http://example.com');
$data->setAudience('http://example.org');
$data->setId('4f1g23a12aa'); var_dump($token->validate($data)); // false, because we created a token that cannot be used before of `time() + 60` $data->setCurrentTime(time() + 61); // changing the validation time to future var_dump($token->validate($data)); // true, because validation information is equals to data contained on the token $data->setCurrentTime(time() + 4000); // changing the validation time to future var_dump($token->validate($data)); // false, because token is expired since current time is greater than exp

我们还可以使用$leeway参数来处理时钟偏差(见下面的注释)。

如果token的声明时间无效,但与验证时间之间的差异小于$leeway,

那么令牌仍然被认为是有效的

'components' => [
'jwt' => [
'class' => \sizeg\jwt\Jwt:class,
'key' => 'secret',
'jwtValidationData' => [
'class' => \sizeg\jwt\JwtValidationData::class,
// configure leeway
'leeway' => 20,
],
],
],
$dataWithLeeway = Yii::$app->jwt->getValidationData();
$dataWithLeeway->setIssuer('http://example.com');
$dataWithLeeway->setAudience('http://example.org');
$dataWithLeeway->setId('4f1g23a12aa'); var_dump($token->validate($dataWithLeeway)); // false, because token can't be used before now() + 60, not within leeway $dataWithLeeway->setCurrentTime($time + 61); // changing the validation time to future var_dump($token->validate($dataWithLeeway)); // true, because current time plus leeway is between "nbf" and "exp" claims $dataWithLeeway->setCurrentTime($time + 3610); // changing the validation time to future but within leeway var_dump($token->validate($dataWithLeeway)); // true, because current time - 20 seconds leeway is less than exp $dataWithLeeway->setCurrentTime($time + 4000); // changing the validation time to future outside of leeway var_dump($token->validate($dataWithLeeway)); // false, because token is expired since current time is greater than exp

重要提示

  • 您必须配置' ValidationData ,通知所有要验证令牌的声明。
  • 如果 ValidationData 包含未在令牌中使用的声明,或者令牌具有未在ValidationData 中配置的声明,则 Token::validate()将忽略这些声明。
  • exp, nbfiat 声明默认在 ValidationData::__construct() 中使用当前 UNIX 时间 (time()).
  • ValidationData的可选$leeway 参数将导致我们在验证基于时间的声明时使用该长度的秒数,

    假装我们在未来的“发出时间”(iat) 和“不在之前”(nbf)索赔,假装我们在过去的更远

    对于“过期时间”(exp)索赔。这允许在发出服务器的时钟与时钟的时间不同的情况下

    验证服务器,如RFC 7519第4.1节所述。

令牌签名

我们可以使用签名来验证令牌在生成后是否未被修改。此扩展实现了Hmac、RSA和ECDSA签名(使用256、384和512)。

重要提示

不允许发送到解析器的字符串指示要使用的签名算法,否则您的应用程序将易受严重的JWT安全漏洞的攻击。

下面的示例是安全的,因为Signer中的选项是硬编码的,不受恶意用户的影响。

Hmac

Hmac signatures are really simple to be used:

$jwt = Yii::$app->jwt;
$signer = $jwt->getSigner('HS256');
$key = $jwt->getKey();
$time = time(); $token = $jwt->getBuilder()
->issuedBy('http://example.com') // Configures the issuer (iss claim)
->permittedFor('http://example.org') // Configures the audience (aud claim)
->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
->issuedAt($time) // Configures the time that the token was issue (iat claim)
->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
->withClaim('uid', 1) // Configures a new claim, called "uid"
->getToken($signer, $key); // Retrieves the generated token var_dump($token->verify($signer, 'testing 1')); // false, because the key is different
var_dump($token->verify($signer, 'testing')); // true, because the key is the same

RSA 和 ECDSA

RSA和ECDSA签名基于公钥和私钥,因此您必须使用私钥生成并使用公钥验证:

$jwt = Yii::$app->jwt;
$signer = $jwt->getSigner('RS256'); // you can use 'ES256' if you're using ECDSA keys
$privateKey = $jwt->getKey('file://{path to your private key}');
$time = time(); $token = $jwt->getBuilder()
->issuedBy('http://example.com') // Configures the issuer (iss claim)
->permittedFor('http://example.org') // Configures the audience (aud claim)
->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
->issuedAt($time) // Configures the time that the token was issue (iat claim)
->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
->withClaim('uid', 1) // Configures a new claim, called "uid"
->getToken($signer, $privateKey); // Retrieves the generated token $publicKey = $jwt->getKey('file://{path to your public key}'); var_dump($token->verify($signer, $publicKey)); // true when the public key was generated by the private one =)

很重要的一点是,如果您使用的是RSA密钥,则不应该调用ECDSA签名者(反之亦然),否则sign()verify()将引发异常!

Yii2基本模板示例

基本方案

  1. 客户端发送凭据。例如,登录+密码
  2. 后端验证它们
  3. 如果凭据是有效的客户端接收令牌
  4. 未来请求的客户端存储令牌

分步使用示例

  1. 创建Yii2应用程序

    在本例中,我们将使用基本模板,但您也可以使用高级模板。

    composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic yii2-jwt-test
  2. 安装组件

    composer require sizeg/yii2-jwt
  3. 在config/web.php中添加 components 部分

    $config = [
    'components' => [
    // other default components here..
    'jwt' => [
    'class' => \sizeg\jwt\Jwt::class,
    'key' => 'secret',
    // You have to configure ValidationData informing all claims you want to validate the token.
    'jwtValidationData' => \app\components\JwtValidationData::class,
    ],
    ],
    ];
  4. 创建JwtValidationData类。在这里,您必须配置ValidationData来通知您要验证令牌的所有声明。

    <?php
    
    namespace app\components;
    
    class JwtValidationData extends \sizeg\jwt\JwtValidationData
    { /**
    * @inheritdoc
    */
    public function init()
    {
    $this->validationData->setIssuer('http://example.com');
    $this->validationData->setAudience('http://example.org');
    $this->validationData->setId('4f1g23a12aa'); parent::init();
    }
    }
  5. 修改方法 app\models\User::findIdentityByAccessToken()

        /**
    * {@inheritdoc}
    * @param \Lcobucci\JWT\Token $token
    */
    public static function findIdentityByAccessToken($token, $type = null)
    {
    foreach (self::$users as $user) {
    if ($user['id'] === (string) $token->getClaim('uid')) {
    return new static($user);
    }
    } return null;
    }
  6. 新建控制器

    <?php
    
    namespace app\controllers;
    
    use sizeg\jwt\Jwt;
    use sizeg\jwt\JwtHttpBearerAuth;
    use Yii;
    use yii\rest\Controller; class RestController extends Controller
    {
    /**
    * @inheritdoc
    */
    public function behaviors()
    {
    $behaviors = parent::behaviors();
    $behaviors['authenticator'] = [
    'class' => JwtHttpBearerAuth::class,
    'optional' => [
    'login',
    ],
    ]; return $behaviors;
    } /**
    * @return \yii\web\Response
    */
    public function actionLogin()
    {
    $request = Yii::$app->getRequest();
    $jwt = Yii::$app->jwt;
    $time = time(); $token = $jwt->getBuilder()
    ->issuedBy($request->getHostInfo())
    ->permittedFor(isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '')
    ->identifiedBy(Yii::$app->security->generateRandomString(10), true) //生成随机的盐值
    ->issuedAt($time)// 设置生成token的时间
    ->expiresAt($time + 3600)//设置token过期时间
    ->withClaim('uid', 100)//配置一个名为uid的新声明
    ->getToken($jwt->getSigner('HS256'), $jwt->getKey()); // Previous implementation
    /*
    $token = $jwt->getBuilder()
    ->setIssuer('http://example.com')// Configures the issuer (iss claim)
    ->setAudience('http://example.org')// Configures the audience (aud claim)
    ->setId('4f1g23a12aa', true)// Configures the id (jti claim), replicating as a header item
    ->setIssuedAt(time())// Configures the time that the token was issue (iat claim)
    ->setExpiration(time() + 3600)// Configures the expiration time of the token (exp claim)
    ->set('uid', 100)// Configures a new claim, called "uid"
    ->sign($signer, $jwt->key)// creates a signature using [[Jwt::$key]]
    ->getToken(); // Retrieves the generated token // 示例
    $jwt = Yii::$app->jwt;
    $signer = $jwt->getSigner('HS256');
    $key = $jwt->getKey();
    $time = time(); // Adoption for lcobucci/jwt ^4.0 version
    $token = $jwt->getBuilder()
    ->issuedBy('http://example.com')// Configures the issuer (iss claim)
    ->permittedFor('http://example.org')// Configures the audience (aud claim)
    ->identifiedBy('4f1g23a12aa', true)// Configures the id (jti claim), replicating as a header item
    ->issuedAt($time)// Configures the time that the token was issue (iat claim)
    ->expiresAt($time + 3600)// Configures the expiration time of the token (exp claim)
    ->withClaim('uid', 100)// Configures a new claim, called "uid"
    ->getToken($signer, $key); // Retrieves the generated token */ return $this->asJson([
    'token' => (string)$token,
    ]);
    } /**
    * @return \yii\web\Response
    */
    public function actionData()
    {
    return $this->asJson([
    'success' => true,
    ]);
    }
    }
  7. 发送简单的登录请求以获取令牌。这里我们不发送任何凭证来简化示例。正如我们在authenticator行为操作login中将authenticator跳过该操作的身份验证检查指定为可选。

  8. 首先,我们尝试向rest/data发送请求,但不带令牌,并且获取错误 Unauthorized

  9. 然后我们重试请求,但已经用令牌添加了Authorization

Yii2 JWT的更多相关文章

  1. 看图理解JWT如何用于单点登录

    单点登录是我比较喜欢的一个技术解决方案,一方面他能够提高产品使用的便利性,另一方面他分离了各个应用都需要的登录服务,对性能以及工作量都有好处.自从上次研究过JWT如何应用于会话管理,加之以前的项目中也 ...

  2. Yii2的深入学习--行为Behavior

    我们先来看下行为在 Yii2 中的使用,如下内容摘自 Yii2中文文档 行为是 [[yii\base\Behavior]] 或其子类的实例.行为,也称为 mixins,可以无须改变类继承关系即可增强一 ...

  3. 网站实现微信登录之回调函数中登录逻辑的处理--基于yii2开发的描述

    上一篇文章网站实现微信登录之嵌入二维码中描述了如何在自己的登录页面内嵌入登录二维码,今天的这篇文章主要是描述下在扫码成功之后微信重定向回网站后登录逻辑的处理,其实也就是验证身份信息,授权用户登录的逻辑 ...

  4. 网站实现微信登录之嵌入二维码——基于yii2开发的描述

    之前写了一篇yii2获取登录前的页面url地址的文章,然后发现自己对于网站实现微信扫码登录功能的实现不是很熟悉,所以,我会写2-3篇的文章来描述下一个站点如何实现微信扫码登录的功能,来复习下微信扫码登 ...

  5. yii2获取登录前的页面url地址--电脑和微信浏览器上的实现以及yii2相关源码的学习

    对于一个有登录限制(权限限制)的网站,用户输入身份验证信息以后,验证成功后跳转到登录前的页面是一项很人性化的功能.那么获取登录前的页面地址就很关键,今天在做一个yii2项目的登录调试时发现了一些很有意 ...

  6. 记一次nginx部署yii2项目时502 bad gateway错误的排查

    周六闲来无事,就试着安装和部署下yii2,安装过程没什么问题,但部署到nginx上时遇到了502 bad gatewary问题,折腾了半天才搞定.这个问题是我以前在部署yii2时没有遇到过的,因此记在 ...

  7. JWT实现token-based会话管理

    上文<3种web会话管理的方式>介绍了3种会话管理的方式,其中token-based的方式有必要从实现层面了解一下.本文主要介绍这方面的内容.上文提到token-based的实现目前有一个 ...

  8. 用JWT来保护我们的ASP.NET Core Web API

    在上一篇博客中,自己动手写了一个Middleware来处理API的授权验证,现在就采用另外一种方式来处理这个授权验证的问题,毕竟现在也 有不少开源的东西可以用,今天用的是JWT. 什么是JWT呢?JW ...

  9. yii2的权限管理系统RBAC简单介绍

    这里有几个概念 权限: 指用户是否可以执行哪些操作,如:编辑.发布.查看回帖 角色 比如:VIP用户组, 高级会员组,中级会员组,初级会员组 VIP用户组:发帖.回帖.删帖.浏览权限 高级会员组:发帖 ...

随机推荐

  1. 一行代码解决MacBook Pro安装VSCode没有应用图标问题

    笔者今天升级了VSCode,安装完后发现Dock(程序坞)没有VSCode的图标了,导致切换应用非常不方便. 具体情况就像下面这张图,VSCode明明开着,但是在Dock找不到VSCode了. 解决办 ...

  2. everspin最新1Gb容量扩大MRAM吸引力

    everspin提供了8/16-bit的DDR4-1333MT/s(667MHz)接口,但与较旧的基于DDR3的MRAM组件一样,时序上的差异使得其难以成为DRAM(动态随机存取器)的直接替代品.   ...

  3. C#实现的一些常见时间格式

    string aa = DateTime.Now.ToShortDateString();//"2019/9/23" string bb = DateTime.Now.ToShor ...

  4. JS淘宝浏览商品

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  5. MySQL基础(6) | check约束

    MySQL基础(6) | check约束 前言 在一些情况下,我们需要字段在指定范围的输入, 例如:性别只能输入 '男'或者'女',余额只能大于0等条件, 我们除了在程序上控制以外,我们还能使用 CH ...

  6. 《手把手教你构建自己的 Linux 系统》学习笔记(5)

    交叉编译是什么? 交叉编译就是在一个系统上,编译生成另外一个系统运行的程序文件. 「硬件体系结构」和「操作系统」的关系是什么? 硬件体系结构也可以称为架构,主要是通过 CPU 的指令集来进行区分的,操 ...

  7. 数据分析----天气预报走向(pygal)

    #!usr/bin/env python #-*- coding:utf-8 _*- """ @author:Administrator @file: 可视化天气预报.p ...

  8. cf1280B

    题意:给出一个n*m的矩阵,矩阵中的元素要么P要么是A 每次可以选择一个的子矩形,然后将矩阵中每一行都变为第一行,或者将矩阵中每一列都变为第一列 要求用最少的次数将矩阵中所有元素都变成A 题解:分类讨 ...

  9. 185.nvm和node.js环境配置

    安装nvm nvm(Node Version Manager)是一个用来管理node版本的工具,我们之所以使用node,是因为我们需要使用node中的npm(Node Package Manager) ...

  10. H5测试方法

    一 功能测试 1 关注页面请求:请求数据是否正确,相应是否正确,是否有重复请求,造成流量浪费,响应速度变慢 2 关注application cache:cokkie值是否正确,清除cokkie后表现是 ...