JWT Token 刷新方案

一:什么是JWT

JWT(JSON Web Token) 是目前最流行的跨域认证解决方案,是一种基于Token的认证授权机制。从JWT的全称可以看出,JWT本身也是Token,JWT自身包含了身份验证所需要的所有信息。因此,服务端不需要存储session信息,大大减轻了服务端的压力。

JWT本质上就是一组字符串,通过"."切割成三个为Base64编码的部分:

• Header:是一个JSON对象,描述JWT的元数据,定义了生成签名的算法以及Token的类型

{
"alg": "HS256",
"typ": "JWT"
}

alg(algorithm):是签名算法,一般是HS256

typ(type):固定值为JWT

• Payload: 也是一个JSON对象,用来存放实际需要传递的数据。JWT规定了7个官方字段,供选用:

{
"iss": "d8b832c0c8caf0d99e9406ed",
"sub": "1",
"aud": "baijunyao",
"iat": "1557066830",
"nbf": "1557066840",
"exp": "1557066850",
"jti": "9e9668d8b8306ed8caf0d94"
}

iss(issuer):发布者

sub(subject):面向的用户

aud(audience):受众

iat(issue at):签发时间的时间戳

nbf(not before):生效时间的时间戳

exp(expiration time):过期时间的时间戳

jti(jwt id):每个JWT自己的唯一id

除了官方定义的这些字段,也可以自己定义一些自己需要的字段

• Signature(签名):

该部分是对前两部分的签名,防止数据篡改,默认使用HS256算法进行签名。签名的方式是把头部和负载分别base64UrlEncode后用"."拼接起来使用Secret进行HS256

Signature = HS256(base64UrlEncode(Header) . base64UrlEncode(Payload), Secret)

 

JWT一共由Header(头部).Payload(负载).Signature(签名)组成,如下:

JWT = base64UrlEncode(Header) . base64UrlEncode(Payload) . HS256(base64UrlEncode(Header) . base64UrlEncode(Payload), Secret)

二:JWT刷新策略

• 利用redis存储jwt(这个可以实现,但是有违jwt的初衷)

ruoyi框架就是用了该种方案,服务端收到请求后,解析token,查看过期时间,当token还有20分钟就要过期时,就刷新token,实际上就是延长token在redis的保存时长。

检查token失效时长:

 刷新token在redis的保存时长:

 

•  redis 不存储JWT token,需要前端配合(比较每一个请求返回体的token与请求体中的token是否一直)

后端会检查每个token的过期时间,一旦发现某个token即将过期,就会在请求头中添加一个新的token。前端在接收到请求时,会拦截该请求并从请求头中获取新的token。如果新旧token不一致,前端会直接更新本地的token,从而确保后续请求能够正常进行。这种方法可以有效避免因token过期而导致的系统闪退问题,提高了系统的稳定性和安全性。

 

以上两种方式都是token自动刷新的后端解决方案。

方案一 (利用redis存储jwt):不需要前端参与,后端利用redis存储jwt token,该种方案有违JWT初衷,可以解决刷新token并发的问题(一个页面同时发送多的请求且token需要刷新的场景);

方案二(redis 不存储JWT token):需要前端参与,该种方案目前感觉不能解决token并发刷新的问题,可以结合redis实现并发刷新的问题,如下:

缓存旧的AccessToken,每次需要刷新Token的时候都把老Token存储一份,可以放在Redis中,或者一个全局变量中,有效时间30s。也就是说30s内带着老Token请求依然有效(该种方案没有实际验证)

Token并发刷新问题:

如果页面都是单请求,自然没有问题,但是页面不可避免的都会有并发的请求。如果有并发请求过来,只有第一个请求可以正常返回,其他的后续所有请求都会失败,因为第一个请求已经刷新的Redis中的时间戳,返回给了前端的新的AccessToken,后续的并发请求自然带着老AccessToken就会全部报错。

 

•  前端控制检测token,无感知刷新

用户登录成功的时候,一次性给两个Token,分别是AcessToken和RefreshToken,AcessToken有效期较短,用于正常请求;RefreshToken有效期可以设置长一些,例如10天、20天,作为刷新AcessToken的凭证。

刷新方案:当AccessToken即将过期的时候,例如提前30分钟,客户端利用RefreshToken请求制定的API获取新的AccessToken并更新本地存储的AccessToken

核心逻辑:

1:登录成功后,jwt生成AcessToken;UUID生成RefreshToken并存储在服务端redis中,设置过期时间;

2:接口返回3个字段AccessToken/RefreshToken/访问令牌过期时间戳;

3:由于RefreshToken存储在服务端redis中,假如这个RefreshToken也过期,则提示重新登录;

疑问:RefreshToken有效期那么长,和直接将AccessToken的有效期延长有什么区别?

答:RefreshToken不像AccessToken那样在大多数请求中被使用,主要是本地检测accessToken快过期的时候才使用,一般本地存储的时候也不叫RefreshToken,前端可以取个别名,混淆代码让攻击者不能直接识别这个就是刷新令牌。

缺点:前端每次请求需要判断token距离过期时间。

优点:后端压力小,代码逻辑改动不大。

该种方案需要将AccessToken和RefreshToken都在前端localStorage保存一份,另外RefreshToken需要在后端redis中也保存一份用于校验RefreshToken的有效性。

Token 并发刷新问题如何解决???

 

posted @   爱喝茶的安迪  阅读(2099)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示