develop / jwt
JWT结合REDIS实现用户认证
v1.0.1
2022-01-28 09:02 UTC
This package is auto-updated.
Last update: 2025-06-13 15:07:10 UTC
README
介绍
jwt认证 https://jwt.io/
- verifyJwt 验证jwt令牌, 项目中间件中引入
- refreshJwt 刷新jwt令牌, 用旧jwt换取新的jwt,旧的jwt加入黑名单
- creatToken 生成jwt令牌, 第一次生成jwt,不验证jwt
- cancelJwt jwt加入黑名单
实际场景
前端
| 服务器生成token的过程中,会有两个时间,一个是token失效时间,一个是token刷新时间,刷新时间肯定比失效时间长,当用户的 token 过期时,你可以拿着过期的token去换取新的token,来保持用户的登陆状态,当然你这个过期token的过期时间必须在刷新时间之内,如果超出了刷新时间,依然返回登录失效, 请重新登录; 旧token换取之后, 会被服务端加入黑名单, 不能再使用;
前端实现无痛刷新token,流程大致为:
- 在axios的拦截器中加入token刷新逻辑
- 当用户token过期时,去向服务器请求新的 token
- 把旧的token替换为新的token
- 然后继续用户当前的请求
- 完美的用户体验
后端
| 后端主动控制jwt失效, 引入redis黑名单
JWT注销黑名单膨胀的解决方案
- 当注销或者刷新jwt, 将用户id作为key, 当前时间作为value, 有效时间为刷新时间减去当前时间戳; 这样的作用, 每个用户的黑名单条目数就从N个变成了1个;
- 当api请求时, 先判断用户id是否在黑名单中存在; 若存在, 判断,jwt的签发时间是否小于黑名单的当前时间; 若小于, 则表示当前jwt已经加入黑名单了, 不能再使用; 这样查找范围就是未过期但又要注销的用户。
- 未过期但要提前注销的用户或 token 数 < 所有已登录用户数 < 所有用户数,此处的『 < 』基本可以看成『远远小于』,所以黑名单策略虽然也算有状态,但是其维护的状态数也是特别小的。
JWT使用流程
- verifyJwt 项目中间间中引入这个方法, 验证jwt合法性
- jwt失效, 需要请求refreshJwt刷新令牌,就jwt加入黑名单
- jwt提示加入黑名单, 需要重新登录
- jwt超过最大刷新时间, 提示需要重新登录
- jwt刷新, 不需要验证是否失效, 但其他情况必须验证, 刷新路由用
refreshJwt
这个路由名称,固定写死,以便核心代码不变动
使用说明
- 配置文件
config.php
说明 | 如果增加新模块, 需要和'api'模块配置一样增加配置文件,且和token实例化的模块名保持一致, demo的模块是'api',故配置也用'api'模块配置
return [
# 配置api模块的key和过期时间,刷新时间
'api' => [
# HMAC生成信息摘要时所使用的密钥
'key' => '202201271430@99999.com',
# 过期时间,单位秒,默认10分钟
'exp' => 10 * 60,
# 刷新时间,单位秒, 默认3天
'ref' => 3 * 24 * 60 * 60
]
];
- 使用
<?php
require_once "../vendor/autoload.php";
use Develop\Jwt\Jwt;
$config = require_once('./config.php');
$token = new Jwt($config, 'api');
$userId = 1;
# 生成jwt令牌
$tokenStr = $token->creatToken($userId);
# 验证jwt令牌
var_dump($token->refreshJwt($tokenStr));
uni-app下解码
| 相关依赖包: npm install --save base-64
getTokenInfo(){
// 解码jwt
let Authorization = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsImlhdCI6MTY0MzMzOTI2MCwibmJmIjoxNjQzMzM5MjYwLCJleHAiOjE2NDMzMzk4NjAsInJlZiI6MTY0MzU5ODQ2MCwiYXVkIjoiYXBpIiwianRpIjoiOTlhYTE1ODI1OThjNTJkMmQzMDVjODY2MmE0MTQwNGIifQ.btXPDDJz0sHqvBTwEovJGcVzjGUmf8Lev_ItSvxmZsY'
let tokenUser = Authorization.split(".")[1];
let obj = JSON.parse(base64.decode(tokenUser))
console.log('jwt转换对象', obj)
console.log('获取jwt刷新时间', obj.ref)
}