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

jwt token 没有撤销机制,一旦泄露或者被窃取有安全隐患,所以 token 有效期也不建议设置的太长
每次请求均生成新的 token 返回给前端有比较大的开销,太粗暴了
利用 redis 验证,但是这样的话 jwt token 的 verify 功能就没有充分利用到,为什么还要用 jwt token?
借鉴 oauth2 的设计使用 refresh_token ,对于小的业务系统应该是更加复杂了

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

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

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

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

www.jianshu.com/p/5334589a2bbe
blog.csdn.net/qq_27900925/article/details/100141226
blog.csdn.net/weixin_39581652/article/details/110801338
codeantenna.com/a/6hbiU2qRvY

如果要用 redis ,那么刷新 token 和不刷新 token 没有太大意义。
如果不用 redis ,那么就是前端 cookie 倒计时,计算 token 到期时间,快到期请求一下刷新 token 的 api

后端提供 refresh_token 接口,返回新的 token ;
前端没有用户操作就不调用,过期就没了。
前端用户一直操作的情况下,在 token 有效期内刷新一次就好了。

没有必要做成过期还要缓冲吧?

80 分钟无打操作重新登录,直接设置 X + 80 分钟的过期时间,超过 X 分钟就取一个新的 token 就好了。想减少拉 token 的次数,把 X 延长就好了。

每个公司的 token 机制都不一样,像我们公司要求
①必须设置过期时间,我们设置的 30 分钟
②当操作频繁时,不能强行过期,就像用户在录入商品信息好不容易填写完了,提交..你给过期了,那会气死
所以保存 token 的同时,保存过期时间。每次请求验证 token 时,校验过期时间,如果剩余时间不足 10 分钟
那么就给 token 延长过期时间,延长 30 分钟,当期间不再有操作就自动过期。

对于登录这种场景,按照一定业务规则生成 token 做 sesison id 就行了,用 JWT 发挥不出太大优势
然后就是 刷新、续订 这些标准操作了

token 无状态,发出去就管不了。要管理 token ,就得有状态,还是 session id 一样的东西,何必要用 JWT 。自己把 session id 和防伪码 base64 编码一下做 token 不更简单?

#3 这感觉和设置“缓冲时间”有些类似,假如 X == 40 ,那么每 40 分钟都会取一个新 token ,120 分钟未操作就让用户重新登录
#2 嗯嗯 这还是什么时候前端去刷新的问题,后端肯定会提供 refresh_token 的接口
#1 我看有些文章用了 redis 存储 token 但是没有用 redis 验证 token ,所以是存了个寂寞?

JWT 虽好,但适用的场景非常有限,不要滥用 JWT 。

绝大多数公司用 JWT 后,然后有一些需求做不到,只能用到 redis 了,比如用户强行下线,一个用户只能一台设备登录到系统。。。等待这些需求,JWT 做不了

#9 是的。比如用户强行下线,redis delete key 然后 jwt 已签发的 token 无法撤回但是由于拦截器拦截请求校验的是 jwt verify 和 redis hasKey ,两者均返回 true 才可以访问资源,所以这样 redis 也能充分利用到了
#4 token 默认的载荷 payload 中就有 exp 字段吧,是个时间戳,我现在是声明了一个东八区给前端,这样在时间上前后端就没有误会

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

是这样的。感谢分享
我的结论就是别用 JWT ,用中心化 Session ,比如 Redis ~

这样就是少了一个变量,少一次判断。另外第三方库可以直接实现。

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

而且一旦有 redis 的话,可以通过 redis 来实现对用户的管控。那样在不考虑合规因素的影响下,也没有必要把 jwt 的过期时间设置的太短,一般以天或者周过期 token 就足够了。

通过存储到数据库给 jwt 添加 session 的特性,不就是另外又发明了一套 session 吗

+1
JWT 其实更适合服务之间用,网关鉴权后生成然后给后续服务传递着用,服务可以拿到可信的用户身份不需要再请求用户服务,请求处理结束就扔掉不用担心踢人之类的事情

zhuanlan.zhihu.com/p/372104412

我觉得加 refresh_token ,这个 token 就是普通的 sessionID ,或者是一个 jwt , 但用户信息从数据库里取。前端定时更新 access_token 就好了。

OIDC 不好用么

上 redis 还要 jwt 干嘛? 只是 session 是正查, jwt revocation 是反查. 每次请求最终还是要去到 redis 查.

#11 我了解一下
#12 网页应用我看 qq 邮箱之类的都是一两个小时没有操作会让用户重新登录的吧,我是觉得一周时间太长(说到底还是要看具体业务)
#15 谢谢分享🙏🏻
#17 我了解一下
#18 🤨

JWT 可以有 JTI 唯一 ID ,需要支持注销的话广播一下 JTI 到各个访问控制点作为黑名单就行了。平时不用每次访问都去 redis 或者数据库验证,使用 JWT 自带的签名校验。

我做了两个项目的登录功能后,目前的方案是:accessToken 过期时间设置短些,如果过期则前端用 refreshToken 获取新 token 即可(对用户来说是无感知的替换了 accessToken )。jwt 和 redis 选择一种方案即可,jwt 本身有附带信息解密即可,如果用 redis 关联 token-用户信息查询也很快。
两种方案都有尝试过,相对更倾向加上 redis 去做记录,如果想要在服务端清除用户本次的登录状态,如果有 redis 记录就方便些;如果用的是纯 jwt 的话,不是很好办,最终还是要服务端记录这个 jwt 。

楼主的过期超时 20 分钟的缓冲,其实就是 refreshToken 方式, 刚开始接触的时候,也用过这种 token 替换 token 的方式,后来发现还有 refreshToken 这种方式,非常适合这种频繁操作时延长 token 有效期的场景

#21 很有用,谢谢分享

每次请求都用中间件判断 jwt ,快过期了就发一个新的,附加到 header 上。拦截器发现新 token 的就替换旧的。

设定过期时间,服务端检测每次请求时,token 还有多久过期,在一定允许时间范围内,重新下发。 这个方案需要 cookie 承接 token

refesh token 总感觉有些多余。一次要整两个 token ,一个 refresh 和一个 access 。

而目的好像只是防止第三方的 js 脚本可以读取 access token ,但是读不了 refresh token 。这个设计还有别的目的吗?

#20 长见识了
#25 我原本也是这样认为的,但是新的认知还得重新建立

从来不用 jwt,都是自己设计一套 token 系统..

刷新啥,让用户退出重新登录

#28 给你补充个 doge