kozlovsv / yii2-jwt-auth
为 Yii2 的 JWT 认证扩展
dev-master
2023-05-05 14:49 UTC
Requires
- php: >=7.2
- ext-json: *
- firebase/php-jwt: ~6.0
- yiisoft/yii2: ~2.0.14
This package is auto-updated.
Last update: 2024-09-05 17:32:20 UTC
README
该库实现了通过 JWT 令牌进行授权。
在授权过程中,使用两个令牌:刷新令牌和访问令牌。访问令牌短生命周期可重复使用,刷新令牌是长期的单次使用。
应用缓存组件(Yii::$app->cache
)用于存储令牌,令牌不会保存到数据库。只存储令牌 ID,一个唯一的 MD5 缓存。因此它是安全的。刷新令牌存储用于重新发放访问令牌。
访问令牌的存储用作令牌白名单,如果存储的令牌不在列表中,则授权不会通过,即使令牌有有效的签名和过期日期
安装
安装此扩展的首选方式是通过 composer。
运行以下命令之一:
php composer.phar require --prefer-dist kozlovsv/yii2-jwt-auth "@dev"
或者
"kozlovsv/yii2-jwt-auth": "@dev"
将以下内容添加到您的 composer.json
文件的 require 部分。
依赖
- PHP 7.2+
- firebase/php-jwt 6.0+
基本用法
将 jwt
组件添加到您的配置文件中,
'components' => [ 'jwt' => [ 'class' => \kozlovsv\jwtauth\Jwt::class, 'accessTokenSecret' => 'Your access token secret', 'refreshTokenSecret' => 'Your refresh token secret', //Not equal to access secret 'alg' => 'HS256', //signing algorithm to use 'durationAccess' => 1800, //default 30 min 'durationRefresh' => 1296000, //default 15 days 'leeway' => 0, //clock skew ], ],
按照以下方式配置 authenticator
行为。
namespace app\controllers; class ExampleController extends \yii\rest\Controller { /** * @inheritdoc */ public function behaviors() { $behaviors = parent::behaviors(); $behaviors['authenticator'] = [ 'class' => \kozlovsv\jwtauth\JwtHttpBearerAuth::class, ]; return $behaviors; } }
您还可以与 CompositeAuth
一起使用,请参阅 文档。
Yii2 基本模板示例
基本方案
认证方案基于此 规范。
- 客户端发送凭证。例如,登录 + 密码。在我们的例子中,这是一个发送到 https://your-domain/rest/login 的 POST 请求。
- 后端验证它们
- 如果凭证有效,客户端将收到一对令牌:刷新和访问
- 客户端将令牌存储在未来的请求中
- 客户端使用访问令牌向后端发送请求进行认证。在我们的例子中,这是一个发送到 https://your-domain/rest/data 的请求。在请求头的部分中,必须指定头
Authorization: Bearer YOUR_ACCESS_TOKEN
- 如果访问令牌已过期,后端将发送带有 401 HTTP 状态的响应
- 客户端发送带有刷新令牌的查询,以更新一对令牌。在我们的例子中,这是一个发送到 https://your-domain/rest/refresh-token 的 POST 请求。刷新令牌的 POST 参数名为
refresh_token='Your refresh token'
- 如果刷新令牌无效,则转到步骤 1
逐步使用示例
-
安装组件
php composer.phar require --prefer-dist kozlovsv/yii2-jwt-auth "@dev"
-
将以下内容添加到 config/web.php 的
components
部分$config = [ 'components' => [ // other default components here.. 'jwt' => [ 'class' => \kozlovsv\jwtauth\Jwt::class, 'accessTokenSecret' => 'Your access token secret', 'refreshTokenSecret' => 'Your refresh token secret', //Not equal to access secret 'alg' => 'HS256', //signing algorithm to use 'durationAccess' => 1800, //default 30 min 'durationRefresh' => 1296000, //default 15 days 'leeway' => 0, //clock skew ], ], ];
-
更改方法
app\models\User::findIdentityByAccessToken()
/** * @param int $token User id * @inheritdoc */ public static function findIdentityByAccessToken($token, $type = null) { $user = self::findOne((int) $token); if ($user) return $user; return null; }
-
创建控制器
<?php namespace app\controllers; use kozlovsv\jwtauth\Jwt; use kozlovsv\jwtauth\RefreshTokenPairBodyAction; use Yii; use yii\web\UnauthorizedHttpException; class RestController extends Controller { /** * @inheritdoc */ public function behaviors() { $behaviors = parent::behaviors(); $behaviors['authenticator'] = [ 'class' => \kozlovsv\jwtauth\JwtHttpBearerAuth::class, 'optional' => [ 'rest/login', 'rest/refresh-token' ], ]; return $behaviors; } public function actions() { //Add to refresh token pair action return [ 'refresh-token' => RefreshTokenPairBodyAction::class, ]; } /** * @return \yii\web\Response * @throws UnauthorizedHttpException * @throws \yii\base\InvalidConfigException */ public function actionLogin() { $model = new \app\models\form\LoginForm([ 'rememberMe' => false, ]); if ($model->load(Yii::$app->request->getBodyParams(), '') && $model->login()) { $user = Yii::$app->user->identity; /** @var Jwt $jwtServ */ $jwtServ = Yii::$app->get('jwt'); list($refreshToken, $acsessToken) = $jwtServ->generateAndSavePairTokens($user->getId()); return $this->asJson([ 'user_id' => $user->getId(), 'access_token' => $acsessToken, 'refresh_token' => $refreshToken, ]); } throw new UnauthorizedHttpException('Your request was made with invalid credentials. ' . implode(',', $model->getFirstErrors())); } /** * @return \yii\web\Response */ public function actionData() { return $this->asJson([ 'success' => true, ]); } }