4

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

 2 years ago
source link: https://www.v2ex.com/t/817906
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  程序员

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

  AllenHua · 20 小时 2 分钟前 · 1477 次点击

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

亮出一些观点

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

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

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

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


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

24 条回复    2021-11-26 09:36:55 +08:00

psnnf

psnnf   19 小时 52 分钟前

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

corningsun

corningsun   19 小时 47 分钟前

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

gengchun

gengchun   19 小时 45 分钟前

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

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

812603834

812603834   19 小时 43 分钟前

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

chendy

chendy   19 小时 39 分钟前

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

xuanbg

xuanbg   19 小时 36 分钟前   ❤️ 2

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

AllenHua

AllenHua   19 小时 35 分钟前

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

xuanbg

xuanbg   19 小时 34 分钟前

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

psnnf

psnnf   19 小时 26 分钟前

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

AllenHua

AllenHua   19 小时 22 分钟前

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

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

是这样的。感谢分享 @812603834

swulling

swulling   19 小时 20 分钟前

我的结论就是别用 JWT ,用中心化 Session ,比如 Redis ~

gengchun

gengchun   19 小时 20 分钟前

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

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

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

mxT52CRuqR6o5

mxT52CRuqR6o5   19 小时 15 分钟前

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

chendy

chendy   19 小时 14 分钟前

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

IvanLi127

IvanLi127   19 小时 2 分钟前

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

zzl22100048

zzl22100048   19 小时 1 分钟前

OIDC 不好用么

joesonw

joesonw   17 小时 39 分钟前

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

AllenHua

AllenHua   14 小时 19 分钟前

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

zhleonix

zhleonix   13 小时 29 分钟前   ❤️ 1

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

hhyyd

hhyyd   11 小时 27 分钟前   ❤️ 1

我做了两个项目的登录功能后,目前的方案是:accessToken 过期时间设置短些,如果过期则前端用 refreshToken 获取新 token 即可(对用户来说是无感知的替换了 accessToken )。jwt 和 redis 选择一种方案即可,jwt 本身有附带信息解密即可,如果用 redis 关联 token-用户信息查询也很快。

两种方案都有尝试过,相对更倾向加上 redis 去做记录,如果想要在服务端清除用户本次的登录状态,如果有 redis 记录就方便些;如果用的是纯 jwt 的话,不是很好办,最终还是要服务端记录这个 jwt 。

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

AllenHua

AllenHua   11 小时 16 分钟前 via iPhone

@hhyyd #21 很有用,谢谢分享

xxfye

xxfye   10 小时 1 分钟前 via Android

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

nl101531

nl101531   54 分钟前 via iPhone

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK