V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
AllenHua
V2EX  ›  程序员

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

  •  
  •   AllenHua · 13 天前 · 2193 次点击

    原帖点我,一般的业务系统里 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 分钟没有使用系统就需要重新登录

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


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

    29 条回复    2021-11-28 09:56:18 +08:00
    psnnf
        1
    psnnf  
       12 天前
    如果要用 redis ,那么刷新 token 和不刷新 token 没有太大意义。
    如果不用 redis ,那么就是前端 cookie 倒计时,计算 token 到期时间,快到期请求一下刷新 token 的 api
    corningsun
        2
    corningsun  
       12 天前
    后端提供 refresh_token 接口,返回新的 token ;
    前端没有用户操作就不调用,过期就没了。
    前端用户一直操作的情况下,在 token 有效期内刷新一次就好了。
    gengchun
        3
    gengchun  
       12 天前
    没有必要做成过期还要缓冲吧?

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

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

    是这样的。感谢分享 @812603834
    swulling
        11
    swulling  
       12 天前
    我的结论就是别用 JWT ,用中心化 Session ,比如 Redis ~
    gengchun
        12
    gengchun  
       12 天前
    @AllenHua 这样就是少了一个变量,少一次判断。另外第三方库可以直接实现。

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

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

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

    楼主的过期超时 20 分钟的缓冲,其实就是 refreshToken 方式, 刚开始接触的时候,也用过这种 token 替换 token 的方式,后来发现还有 refreshToken 这种方式,非常适合这种频繁操作时延长 token 有效期的场景
    AllenHua
        22
    AllenHua  
    OP
       12 天前 via iPhone
    @hhyyd #21 很有用,谢谢分享
    xxfye
        23
    xxfye  
       12 天前 via Android
    每次请求都用中间件判断 jwt ,快过期了就发一个新的,附加到 header 上。拦截器发现新 token 的就替换旧的。
    nl101531
        24
    nl101531  
       12 天前 via iPhone
    设定过期时间,服务端检测每次请求时,token 还有多久过期,在一定允许时间范围内,重新下发。 这个方案需要 cookie 承接 token
    gengchun
        25
    gengchun  
       11 天前
    @hhyyd refesh token 总感觉有些多余。一次要整两个 token ,一个 refresh 和一个 access 。

    而目的好像只是防止第三方的 js 脚本可以读取 access token ,但是读不了 refresh token 。这个设计还有别的目的吗?
    AllenHua
        26
    AllenHua  
    OP
       11 天前
    @zhleonix #20 长见识了
    @gengchun #25 我原本也是这样认为的,但是新的认知还得重新建立
    chtcrack
        27
    chtcrack  
       10 天前
    从来不用 jwt,都是自己设计一套 token 系统..
    kssss
        28
    kssss  
       10 天前
    刷新啥,让用户退出重新登录
    AllenHua
        29
    AllenHua  
    OP
       10 天前 via iPhone
    @kssss #28 给你补充个 doge
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4027 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 06:33 · PVG 14:33 · LAX 22:33 · JFK 01:33
    ♥ Do have faith in what you're doing.