观帖“登录最佳实践”有感, jwt token 如何优雅的刷新?

2021-11-25 14:28:50 +08:00
 AllenHua

原帖点我,一般的业务系统里 jwt token 都是如何刷新的?有没有最佳实践。

亮出一些观点

在 SpringBoot + redis + jwt token 的技术实践中,我的一点想法:

  1. 充分利用 jwt token 和 redis ,在拦截器中校验用户请求是否有效使用 jwt token 的 verify 和 redis hasKey 联合校验
  2. 设置一个 jwt token 已过期的缓冲区,比如设计 token 有效期 1 小时,但是在超时的 20 分钟内用户可以拿现有 token 换一个新的 token ,实现 token 的刷新。如果用户在此期间一直有操作系统,那么就不用重新登录。如果用户有 80 分钟没有使用系统就需要重新登录

为的是服务器开销和业务需求之间寻求平衡。


网上搜到一些讨论(如下),欢迎大家畅所欲言

4475 次点击
所在节点    程序员
30 条回复
psnnf
2021-11-25 14:38:43 +08:00
如果要用 redis ,那么刷新 token 和不刷新 token 没有太大意义。
如果不用 redis ,那么就是前端 cookie 倒计时,计算 token 到期时间,快到期请求一下刷新 token 的 api
corningsun
2021-11-25 14:44:26 +08:00
后端提供 refresh_token 接口,返回新的 token ;
前端没有用户操作就不调用,过期就没了。
前端用户一直操作的情况下,在 token 有效期内刷新一次就好了。
gengchun
2021-11-25 14:46:07 +08:00
没有必要做成过期还要缓冲吧?

80 分钟无打操作重新登录,直接设置 X + 80 分钟的过期时间,超过 X 分钟就取一个新的 token 就好了。想减少拉 token 的次数,把 X 延长就好了。
812603834
2021-11-25 14:48:07 +08:00
每个公司的 token 机制都不一样,像我们公司要求
①必须设置过期时间,我们设置的 30 分钟
②当操作频繁时,不能强行过期,就像用户在录入商品信息好不容易填写完了,提交..你给过期了,那会气死
所以保存 token 的同时,保存过期时间。每次请求验证 token 时,校验过期时间,如果剩余时间不足 10 分钟
那么就给 token 延长过期时间,延长 30 分钟,当期间不再有操作就自动过期。
chendy
2021-11-25 14:52:29 +08:00
对于登录这种场景,按照一定业务规则生成 token 做 sesison id 就行了,用 JWT 发挥不出太大优势
然后就是 刷新、续订 这些标准操作了
xuanbg
2021-11-25 14:54:39 +08:00
token 无状态,发出去就管不了。要管理 token ,就得有状态,还是 session id 一样的东西,何必要用 JWT 。自己把 session id 和防伪码 base64 编码一下做 token 不更简单?
AllenHua
2021-11-25 14:56:17 +08:00
@gengchun #3 这感觉和设置“缓冲时间”有些类似,假如 X == 40 ,那么每 40 分钟都会取一个新 token ,120 分钟未操作就让用户重新登录
@corningsun #2 嗯嗯 这还是什么时候前端去刷新的问题,后端肯定会提供 refresh_token 的接口
@psnnf #1 我看有些文章用了 redis 存储 token 但是没有用 redis 验证 token ,所以是存了个寂寞?
xuanbg
2021-11-25 14:56:46 +08:00
JWT 虽好,但适用的场景非常有限,不要滥用 JWT 。
psnnf
2021-11-25 15:05:15 +08:00
@AllenHua 绝大多数公司用 JWT 后,然后有一些需求做不到,只能用到 redis 了,比如用户强行下线,一个用户只能一台设备登录到系统。。。等待这些需求,JWT 做不了
AllenHua
2021-11-25 15:09:36 +08:00
@psnnf #9 是的。比如用户强行下线,redis delete key 然后 jwt 已签发的 token 无法撤回但是由于拦截器拦截请求校验的是 jwt verify 和 redis hasKey ,两者均返回 true 才可以访问资源,所以这样 redis 也能充分利用到了
@812603834 #4 token 默认的载荷 payload 中就有 exp 字段吧,是个时间戳,我现在是声明了一个东八区给前端,这样在时间上前后端就没有误会

> 如果剩余时间不足 10 分钟
那么就给 token 延长过期时间,延长 30 分钟,当期间不再有操作就自动过期。

是这样的。感谢分享 @812603834
swulling
2021-11-25 15:10:51 +08:00
我的结论就是别用 JWT ,用中心化 Session ,比如 Redis ~
gengchun
2021-11-25 15:11:17 +08:00
@AllenHua 这样就是少了一个变量,少一次判断。另外第三方库可以直接实现。

个人觉得,放了 redis 其实是为了实现流控,计费,或者蜜罐这些功能的话。

而且一旦有 redis 的话,可以通过 redis 来实现对用户的管控。那样在不考虑合规因素的影响下,也没有必要把 jwt 的过期时间设置的太短,一般以天或者周过期 token 就足够了。
mxT52CRuqR6o5
2021-11-25 15:16:24 +08:00
通过存储到数据库给 jwt 添加 session 的特性,不就是另外又发明了一套 session 吗
chendy
2021-11-25 15:16:46 +08:00
@xuanbg +1
JWT 其实更适合服务之间用,网关鉴权后生成然后给后续服务传递着用,服务可以拿到可信的用户身份不需要再请求用户服务,请求处理结束就扔掉不用担心踢人之类的事情
aboat365
2021-11-25 15:21:38 +08:00
IvanLi127
2021-11-25 15:29:09 +08:00
我觉得加 refresh_token ,这个 token 就是普通的 sessionID ,或者是一个 jwt , 但用户信息从数据库里取。前端定时更新 access_token 就好了。
zzl22100048
2021-11-25 15:30:25 +08:00
OIDC 不好用么
joesonw
2021-11-25 16:52:09 +08:00
上 redis 还要 jwt 干嘛? 只是 session 是正查, jwt revocation 是反查. 每次请求最终还是要去到 redis 查.
AllenHua
2021-11-25 20:12:04 +08:00
@swulling #11 我了解一下
@gengchun #12 网页应用我看 qq 邮箱之类的都是一两个小时没有操作会让用户重新登录的吧,我是觉得一周时间太长(说到底还是要看具体业务)
@aboat365 #15 谢谢分享🙏🏻
@zzl22100048 #17 我了解一下
@joesonw #18 🤨
zhleonix
2021-11-25 21:02:17 +08:00
JWT 可以有 JTI 唯一 ID ,需要支持注销的话广播一下 JTI 到各个访问控制点作为黑名单就行了。平时不用每次访问都去 redis 或者数据库验证,使用 JWT 自带的签名校验。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/817906

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX