JWT双令牌认证实现无感Token自动续约

news/2024/9/24 16:43:32/

一、JWT概念

JSON Web Token (JWT)是一个开放标准(RFC 7519) ,它定义了一种紧凑和自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。此信息可以进行验证和信任,因为它是经过数字签名的。JWT 可以使用机密(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
虽然可以对 JWT 进行加密,以便在各方之间提供保密性,但是我们将关注已签名的Token。签名Token可以验证其中包含的声明的完整性,而加密Token可以向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,该签名还证明只有持有私钥的一方才是对其进行签名的一方( 签名技术是保证传输的信息不可抵赖,并不能保证信息传输的安全 )
官网地址:https://jwt.io

二、JWT 原理

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

{"姓名": "开源技术小栈","角色": "管理员","到期时间": "2028年12月11日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。
服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

三、JWT 数据结构

编码后的数据结构
在这里插入图片描述
它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。JWT 的三个部分依次如下

Header(头部)
Payload(负载)
Signature(签名)

写成一行,就是下面的样子。Header.Payload.Signature
在这里插入图片描述

三、JWT 认证流程

在这里插入图片描述
认证流程流程说明:
1、浏览器发起请求登陆,用户携带用户名和密码等了
2、服务端验证身份,根据算法,将用户标识符打包生成 Token,
3、服务器返回JWT信息给浏览器,JWT不包含敏感信息
4、浏览器发起请求获取用户资料,把刚刚拿到的 Token一起发送给服务
5、器服务器发现数据中有 Token,验证身份是否合法
6、服务器根据当前Token解析返回该用户的用户资料

双令牌解决方案

在前后端分离的开发模式下,前端用户登录成功后后端服务会给用户颁发一个JWT的access_token。前端在接收到JWT的access_token后会将access_token存储到浏览器LocalStorage中。
后续每次请求都会将此access_token放在请求头中传递到后端服务,后端服务会有一个过滤器对access_token进行拦截校验,校验access_token是否过期,如果access_token过期则会让前端跳转到登录页面重新登录。因为JWT的access_token中一般会包含用户的基础信息,为了保证JWT的access_token的安全性,一般会将JWT的access_token的过期时间设置的比较短。
但是这样又会导致前端用户需要频繁登录(access_token过期),甚至有的表单比较复杂,前端用户在填写表单时需要思考较长时间,等真正提交表单时后端校验发现access_token过期失效了不得不跳转到登录页面。
如果真发生了这种情况前端用户肯定是要吐槽的,对用户体验非常不友好。例如:access_token有效期是2h,用户一直在使用客户端考试,使用的过程中,access_token到期跳转到登录页面邀请重新登录。心里想说什么垃圾系统,过了2个小时又要重新登录!我他妈想骂人了,一万个…
本篇内容就是在前端用户无感知的情况下实现access_token的自动续期,避免频繁登录、表单填写内容丢失情况的发生。以及access_token和refresh_token很巧妙的实效设置,达到双令牌刷新、续期。AccessToken和RefreshToken

四、什么是 Access Token ?

Access Token 用于基于 Token 的认证模式,允许应用访问一个资源 API。用户认证授权成功后,服务端会签发 Access Token 给应用。应用需要携带 Access Token 访问资源 API,资源服务 API 会通过拦截器查验 Access Token 中的 scope 字段是否包含特定的权限项目,从而决定是否返回资源。

五、什么是 Refresh Token ?

通常Access Token有效时间通常较短。通常用户在获取资源的时候需要携带 Access Token,当 Access Token 过期后,用户需要获取一个新的 AccessToken。这时候就需要Refresh Token了。Refresh Token 用于获取新的 AccessToken。这样可以缩短 AccessToken 的过期时间保证安全,同时又不会因为频繁过期重新要求用户登录。用户在初次认证时,Refresh Token 会和AccessToken 一起返回。应用必须安全地存储 Refresh Token,它的重要性和密码是一样的,因为 Refresh Token 能够一直让用户保持登录。
在这里插入图片描述

{"code": 0,"msg": "success","data": {"token_type": "Bearer","expires_in": 7200,"access_token": "eyJ0eXA1NiJ9.eyJpc3MiOikifX0._kwtyMsMI0ML0o","refresh_token": "eyJ0eXiJIUzI1NiJ9.eyJpc3MiOifX0.mYSXrpoNpU"}}
}

客户端应用携带 Refresh Token 向服务端点发起请求时,服务端每次都会返回相同的Refresh Token 和新的 AccessToken,直到 Refresh Token 过期。
在这里插入图片描述

{"code": 0,"msg": "success","data": {"token_type": "Bearer","expires_in": 7200,"access_token": "eyJ0eXA1NiJ9.eyJpc3MiOikifX0._kwtyMsMI0ML0o","refresh_token": "eyJ0eXiJIUzI1NiJ9.eyJpc3MiOifX0.mYSXrpoNpU"}}
}

代码实现实现配置参数说明。access_token设置为2小时过期,而refresh_token设置7天过期。
这样7天内,如果access_token过期了,那就可以用refresh_token来刷新拿到新的access_token。只要不超过7天内未访问系统,那就可以一直是登录状态,可以无限续签,不需要登录。如果超过7天未访问系统,那么refresh_token也就过期了,这时候需要重新登录了。

六、安装插件

composer require tinywan/jwt
插件地址:https://www.workerman.net/plugin/10插件配置配置文件config/plugin/tinywan/jwt

return ['enable' => true,'jwt' => [// 算法类型 HS256、HS384、HS512、RS256、RS384、RS512、ES256、ES384、Ed25519'algorithms' => 'HS256',// access令牌秘钥'access_secret_key' => '2024d3d3LmJq',// access令牌过期时间,单位:秒。默认 2 小时'access_exp' => 7200,// refresh令牌秘钥'refresh_secret_key' => '2022KTxigxc9o50c',// refresh令牌过期时间,单位:秒。默认 7 天'refresh_exp' => 604800,// refresh 令牌是否禁用,默认不禁用 false'refresh_disable' => false,// 令牌签发者'iss' => 'webman.tinywan.cn',...
];

access_token设置access_exp为2小时过期refresh_token设置refresh_exp为7天过期
生成令牌

$user = ['id'  => 2024, 'name'  => 'Tinywan','email' => 'Tinywan@163.com'
];
$token = Tinywan\Jwt\JwtToken::generateToken($user);
var_dump(json_encode($token));

输出(json格式)

{"token_type": "Bearer","expires_in": 36000,"access_token": "eyJ0eXAiOiJAUR-Gqtnk9LUPO8IDrLK7tjCwQZ7CI...","refresh_token": "eyJ0eXAiOiJIEGkKprvcccccQvsTJaOyNy8yweZc..."
}

参数描述
在这里插入图片描述

六、中间件拦截器

/*** @desc 中间件拦截器* @author Tinywan(ShaoBo Wan)*/
declare(strict_types=1);namespace app\middleware;use Tinywan\ExceptionHandler\Exception\ForbiddenHttpException;
use Tinywan\ExceptionHandler\Exception\UnauthorizedHttpException;
use Tinywan\Jwt\JwtToken;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;class AuthorizationMiddleware implements MiddlewareInterface
{/*** @param Request $request* @param callable $handler* @return Response* @throws ForbiddenHttpException|UnauthorizedHttpException*/public function process(Request $request, callable $handler): Response{$request->userId = JwtToken::getCurrentId();if (0 === $request->userId) {throw new UnauthorizedHttpException();}return $handler($request);}
}

中间件拦截器中是对 access_token进行请求拦截校验,判断access_token是否有效。如果当前用户access_token无效,则直接拦截请求并返回UnauthorizedHttpException认证失败异常类响应。令牌验证 无效 响应参考示例

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8{"code": 0,"msg": "令牌会话已过期,请再次登录!","data": {}
}

令牌验证 通过 响应参考示例

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8{"code": 0,"msg": "success","data": {"id": 202801,"username": "Tinywan"},
}

七、刷新令牌通

通过以上可以看出我们设置的access_token为2小时过期后,服务端会返回一个401的HTTP状态码HTTP/1.1 401 Unauthorized,参考如下所示:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8{"code": 0,"msg": "身份验证会话已过期,请重新登录!","data": {}
}

现在access_token是2小时已过期了,2小时之后就需要重新登录了。也就是前端需要跳转到登录页面。这样显然体验不好,接下来实现用refresh_token来刷新获取新的访问令牌access_token
通过调用刷新令牌refreshToken()方法来获取最新的访问令牌access_token
刷新令牌伪代码参考

/*** @desc: 刷新令牌* @return Response* @author Tinywan(ShaoBo Wan)*/
public function refreshToken(): Response
{$res = \Tinywan\Jwt\JwtToken::refreshToken();return response_json(0,'success',$res);
}

在这里插入图片描述
CUL 模拟请求

curl --request GET \--url http://127.0.0.1:8888/oauth/refresh-token \--header 'Accept: */*' \--header 'Accept-Encoding: gzip, deflate, br' \--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ3ZWJtYW4udGlueXdhbi5jbiIsImF1ZCI6IndlYm1hbi50aW55d2FuLmNuIiwiaWF0IjoxNzI0MTM3MzQzLCJuYmYiOjE3MjQxMzczNDMsImV4cCI6MTcyNDc0MjE0MywiZXh0ZW5kIjp7ImlkIjoyMDIyMDAwMSwidXNlcm5hbWUiOiJ3ZWJtYW4iLCJtb2JpbGUiOiIxMzY2OTM2MTE5MiIsImVtYWlsIjoiVGlueXdhbkAxNjMuY29tIiwiYXZhdGFyIjoiaHR0cHM6Ly9saXZlLW9zcy5iYWlkdS5jb20vYXNzZXRzL2ltYWdlcy9hdmF0YXJzLzZhdmF0YXIuanBnIiwicGFzc3dvcmQiOiIkMnkkMTAkRm1Ka0RJV2JWN2hDTEl0VWV1amhpT0dibDEuVHYwUjRXNEJnaFhZWWNkcThQTGJVNm5lTGUiLCJpc19lbmFibGVkIjoxLCJjcmVhdGVfdGltZSI6IjIwMjEtMTEtMTIgMTA6NDg6NTkifX0.3Ii4Og8N6M7rk9GDxT_RydX12FdioGJUXvJU4wm5AwA' \--header 'Connection: keep-alive' \--header 'User-Agent: PostmanRuntime-ApipostRuntime/1.1.0'

注意:这时候请求认证Header的Authorization: Bearer 传的值是refresh_token令牌,而不是access_token令牌.
通过以上请求带上有效的refresh_token,拿到新的access_token和refresh_token

HTTP/1.1 402 Unauthorized
Content-Type: application/json;charset=UTF-8{"code": 0,"msg": "刷新令牌会话已过期,请重新登录!","data": {}
}

注意:这里返回的HTTP状态码是402,当然了该状态码可以通过配置文件进行配置。可以看出我们设置的refresh_token超过7天也就过期了,这时候需要前端跳转到登录页面让用户重新登录了。

七、前端伪代码

async function refreshToken() {const res = await axios.get("http://127.0.0.1:8888/oauth/refresh-token", {params: { refresh_token: localStorage.getItem("refresh_token") },});localStorage.setItem("access_token", res.data.access_token || "");localStorage.setItem("refresh_token", res.data.refresh_token || "");return res;
}axios.interceptors.response.use((response) => response,async (err) => {let { data, config } = err.response;if (data.statusCode === 401 && config.url.includes("/oauth/refresh-token")) {const res = await refreshToken();if (res.status === 200) {return axios(config);} else {alert("登录过期,请重新登录");return Promise.reject(res.data);}} else {return err.response;}}
);var first_sceen__time = (+new Date());
if ("" == 1 && document.getElementById('js_content')) {
document.getElementById('js_content').addEventListener("selectstart",function(e){ e.preventDefault(); });
}

http://www.ppmy.cn/news/1529889.html

相关文章

springboot中药材进存销管理系统

基于springbootvue实现的中药材进存销管理系统 (源码L文ppt)4-079 4 系统总体设计 4.1系统功能结构设计图 根据需求说明设计系统各功能模块。采用模块化设计方法实现一个复杂结构进行简化,分成一个个小的容易解决的板块,然…

了解什么是双软认证

“双软认证”是指软件企业的认定和软件产品的登记。这是我国对软件企业和软件产品的权威资质认证。以下是具体介绍: 1. 软件企业认定: ● 定义:以计算机软件开发生产、系统集成、应用服务和其他相应技术服务为其经营业务和主要经营收入&…

智慧安防监控EasyCVR视频汇聚管理平台如何修改视频流分辨率?

智慧安防监控EasyCVR视频管理平台能在复杂的网络环境中,将前端监控设备进行统一集中接入与汇聚管理。EasyCVR平台支持H.264/H.265视频压缩技术,可在4G/5G/WIFI/宽带等网络环境下,传输720P/1080P/2K/4K高清视频。视频流经平台处理后&#xff0…

Java后端框架---Spring

目录 一.Spring是什么? 二.Spring Hello World 搭建 三.XML配置bean管理 1.bean标签 2.依赖注入 3.依赖注入的补充 四.注解配置bean管理 1.开启注解扫描 2.使用注解对类进行配置 3.自动注入 五.面向切面编程AOP 1.概述 2.通知 六.spring事务管理 1.数据库…

SpringMVC 中的域对象共享数据

文章目录 一、向 request 域对象共享数据二、Model、ModelMap、Map 的关系三、向 session 域共享数据四、向 application 域共享数据五、总结 在当今这个技术飞速发展的时代,SpringMVC 框架在众多的 Java 开发领域中占据着至关重要的地位。在 SpringMVC 框架当中&am…

OpenCV系列教程二:基本图像增强(数值运算)、滤波器(去噪、边缘检测)

文章目录 一、基本图像增强(数值运算)1.1 加法 (cv2.add)1.1.1 图像与标量相加(调节亮度)1.1.2 图像与图像相加(两个图像shape要相同)1.1.3 图像的加权加法(渐变切换&…

面试知识点总结篇三

一、arm中断流程和函数 ARM 中断流程 中断触发保存上下文中断向量表执行ISR - 清除中断标志恢复上下文返回中断 二、STM32任务间通信有哪些方式 消息队列、 信号量、共享内存、任务通知 三、uboot内存没驱动之前是怎么操作的 硬件初始化内存检测设置内存映射控制台初始化…

idea 恢复 pom 文件呈现灰色并带删除线

今天在 idea 中导入别人的项目时发现有几个 pom 文件是灰色的并带删除线。 可以用以下方式解决: 打开file - settings - build,execution,deployment - Build Tools - Maven - Ignored Files 把 pom.xml 前面的复选框去掉,去掉之后,点击 appl…