同志们,技术问题来了,大家讨论下, jwt 续签为什么要使用双 token - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
lusxh
V2EX    程序员

同志们,技术问题来了,大家讨论下, jwt 续签为什么要使用双 token

  •  
  •   lusxh 5 小时 53 分钟前 via iPhone 2923 次点击
    Access Token 和 Refresh Token 有什么区别呢?为什么需要两个 token? 有什么优点吗?
    第 1 条附言    2 小时 49 分钟前
    看了各位老哥的评论,很有启发,主要集中在性能和可控中。
    双 token:

    性能:Access Token:cpu 解密开销换取数据库查询开销。 性能好,但是不安全了 (有 15 分钟危险期) 用户被拉黑或者被禁用,还可以继续访问系统,为了性能牺牲了 15 分钟的安全性。

    可控:Refresh Token:到下一次换取 Access Token 时,发现用户的状态是否改变,决定是否下发 Access Token

    安全:没看出来哪里安全了。

    单 token+redis:
    每次访问接口都查 redis 中用户的状态,用户状态发生改变后就不能访问系统了 ,反而更安全, 性能也不见得差么。

    感觉这次能把这个问题讨论清楚了。
    43 条回复    2025-12-18 16:47:32 +08:00
    tanxnative
        1
    tanxnative  
       5 小时 51 分钟前
    抖音上徐庶说, 这样安全!
    shakaraka
        2
    shakaraka  
    PRO
       5 小时 40 分钟前   9
    首先,这种问题在 v2 算是日经贴的了,搜一下就有了,其次直接问 GPT 就有很标准的答案的。

    另外我再回答一下吧

    Access Token 是让网关去进行身份认证的,不需要查询数据库,数据库没有压力,高流量场景不需要查询 redis 、db 等,也支持分布式,同时 Access Token 不会授权很长时间

    Refresh Token 是需要查询 db 的,因为要对用户进行一些业务逻辑判断,分析是否能够重新下发 Access Token
    ty29022
        3
    ty29022  
       5 小时 40 分钟前   1
    一种工程上的 trade off
    本质上是想把无状态的 jwt token 变成有状态的
    然后把每次状态的查询成本摊到 n 秒一次(refresh token 的过期时间)
    zhlssg
        4
    zhlssg  
       5 小时 35 分钟前
    无感知续签,token 是有有效期的,Refresh 可以在用户过期时续签 token ,无需用户重新登录
    yiqiao
        5
    yiqiao  
       5 小时 34 分钟前
    @shakaraka 确实,好像见过不止一次了。不过很多人都不用 RefreshToken ,Access Token 过期就直接重新登录了。
    shakaraka
        6
    shakaraka  
    PRO
       5 小时 27 分钟前
    @yiqiao #5 想要完全后端类决定前端生死的只能是 session 的模式。没有比这种掌控力更强了。token 模式多数用在互联网产品中。像是金融客户系统就多数是类似 session 模式的
    cfancc
        7
    cfancc  
       5 小时 13 分钟前
    问 ai 或者百度
    zxjxzj9
        8
    zxjxzj9  
       5 小时 6 分钟前
    理论上一直用一个 token 来鉴权也不是不行,问题就在于 jwt 这样的无状态 token 不改秘钥不设置过期时间,token 发下去就会永久有效。为了让服务端有办法能让 token 过期但是又利用无状态特性,实践上把这一个 token 拆成两个,验证的时候用 access token ,让鉴权的时候不需要访问数据库直接端侧完成。refresh token 完全可以理解成一个 session id, 只要会话不过期服务端就可以给你续签,好处就是直接把请求 db 的次数用 access token 全压下去了。 这两个 token 也没明说非要用 jwt ,只不过如果要用的话全用 jwt 可以少造点轮子。
    yeqizhang
        9
    yeqizhang  
       4 小时 34 分钟前 via Android   1
    虽然是月经帖,但我还是没得出标准结论,之前有从网络安全来讲的,也见过像第三方授权如对接微信那种又是不一样的,今天又在这里说查不查数据库的……
    zuixinwenyue
        10
    zuixinwenyue  
       4 小时 26 分钟前
    只是表示讨论,国内好多大厂对外开放的 api 都是双 token 模式,肯定是有一定优势的,我说一下我自己的理解吧。
    zuixinwenyue
        11
    zuixinwenyue  
       4 小时 26 分钟前
    @zuixinwenyue 没想到拍了回车就回复了
    lusxh
        12
    lusxh  
    OP
       4 小时 19 分钟前 via iPhone
    @shakaraka 只是为了减轻数据库的压力吗?两个 token 都可以不查数据库么。
    lusxh
        13
    lusxh  
    OP
       4 小时 16 分钟前 via iPhone
    @yeqizhang 确实看到很多地方讨论这个问题,说什么的都有,面试有时候也被问到,随便几句就敷衍过去了,就是不自信,感觉没有触及到深处
    zuixinwenyue
        14
    zuixinwenyue  
       4 小时 15 分钟前
    @zuixinwenyue
    先说一些传统的 token 模式有状态和无状态
    1.有状态:cookie 或者 uuid 生成一个 token 放请求头里,这些都属于有状态。服务侧缓存 token 信息
    2.无状态: jwt 本身就带了 token 的信息&用户信息;

    分析一下痛点,可能举例不完善:

    有状态: 每次请求进来需要查询缓存啊 or 数据库,影响性能
    可以做判断 token 是否存在啊 用户是否登录过期啊 用户有没有被禁用 也可以做到用户信息发生修改 踢用户下线之类的操作 只允许一端登录啊。可控性非常大;

    无状态: 无状态的话就不需要查询数据库了,从性能来讲肯定是比有状态要好的,服务侧拿到只需要验签就可以。
    缺点也很明显,上面说到有状态能做的都不行

    双 token 我自己感觉是折中了一下 在需要性能+用户可控方面折中,一般来讲 accessToken 是无状态的用于快速验证 过期时间较短,refreshToken 是有状态 用于判断用户信息之类的操作 过期时间较长。这样就可以在性能和用户可控方面折中啦。
    以上是我的浅见
    SethShi
        15
    SethShi  
       4 小时 13 分钟前
    提一嘴.
    JWT 没有双 token, 它只定义了 token 的格式
    楼上说的国内大厂的那种是 OAuth 2.0

    至于你要问的问题, 楼上的答案都差不多了, 当然不排除很多人是“为了遵守协议( OAuth2 )”而盲目使用双 Token
    zuixinwenyue
        16
    zuixinwenyue  
       4 小时 12 分钟前
    网上说什么的都有 有说是为了让用户无感续签,之前做的项目是有状态的 每次用户请求进来都会给 token 续期。我之前面试也被问过这个问题 我回答的就是用户带 token 进来验证成功就续期一下 现在想起来问的应该是双 token 。但是我理解使用双 token 不是为了续签,更是为了追求性能+用户可控性一个折中的方案;
    zuixinwenyue
        17
    zuixinwenyue  
       4 小时 11 分钟前
    @SethShi oauth2.0 是提供授权码,最后用授权码换回来的就是双 token 。
    Ketteiron
        18
    Ketteiron  
       4 小时 10 分钟前
    @yeqizhang #9 标准结论一直都有啊,用不用 jwt 只看需不需要 jwt 。
    jwt 实际上是拿 cpu 解密开销换取数据库查询开销,为了安全性可能会双 token(15 分钟危险期) or 单 token+redis(秒级封禁)。除此之外有非常多的组合方法,但各有侧重点没有高下之分,软件开发不存在通用最优解。
    softlight
        19
    softlight  
       4 小时 7 分钟前
    看了下,access token 只需要校验 token 是否有效,无需外部依赖查询。Refresh Token 分发 Access Token 时,需要额外查询,比如用户是否被禁用, 权限是否发生变更,账号是否被封。 在性能和可控当中,做这个折衷选择
    shakaraka
        20
    shakaraka  
    PRO
       3 小时 57 分钟前
    @lusxh #12 你这句话完整复制给 AI 就有很详细的回复了,这里不赘述了
    lusxh
        21
    lusxh  
    OP
       3 小时 41 分钟前 via iPhone
    @Ketteiron 老哥说的很精准啊
    SethShi
        22
    SethShi  
       3 小时 37 分钟前
    @zuixinwenyue 都是 OAuth 协议标准的定义呀
    lusxh
        23
    lusxh  
    OP
       3 小时 37 分钟前 via iPhone
    @shakaraka 我不想问 ai ,我就想和同志们讨论下。要不然下午 6 点半才下班,时间太难熬了
    litchinn
        24
    litchinn  
       3 小时 32 分钟前
    一个 token 怎么让用户无感续签呢
    sentinelK
        25
    sentinelK  
       3 小时 26 分钟前
    Refresh Token 的存在,就是因为要验证其“续签 token 的合法性和合理性”

    你可以把 Refresh Token ,看成是自动重新登录的“用户名+密码”。

    当 token 对应的账户被封禁、密码修改等操作时,对应的 Refresh Token 也会同时作废。也就是当前用户的操作权限也就到这个 token 生命周期结束为止。

    至于说为什么自动登录不使用用户名+密码作为参数。
    因为,用户名+密码是最高级别的用户信息,不应该被保存和频繁录入、传输。
    sentinelK
        26
    sentinelK  
       3 小时 25 分钟前
    至于说,为何不每次请求都验证 token 对应的用户合法性,这是基于性能的妥协。
    sentinelK
        27
    sentinelK  
       3 小时 22 分钟前
    btw:JWT 是一种 token 的实现形式。
    和“是否采用双 Token”、“是否遵循 OAuth 2.0”等话题风马牛不相及。

    所以,“ jwt 续签为什么要使用双 token”严格来讲是个错误命题。
    canteon
        28
    canteon  
       3 小时 14 分钟前
    这是一个球疼怪子弹的问题
    photon006
        29
    photon006  
       3 小时 14 分钟前
    如果只有一个 accessToken ,快到期了,用户前几秒还在填信息,下一秒点提交跳登录页。。。What the fuck!!!
    zxjxzj9
        30
    zxjxzj9  
       2 小时 58 分钟前   1
    @lusxh 操作上当然都可以,你把 refreshtoken 做成过期时间很长的 jwt ,每次校验 refresh 的时候也不用过数据库。问题就在于这样做拆分就没有意义了,直接用 access token 校验不就好了么。你这样问的就是,我不查数据库有没有办法维护一个 token 的状态,那答案肯定是否定的。

    不过 oauth2.0 并没有规定这些乱七八糟的,这个框架只明确规定了客户端应该利用获取 access token 这个行为来获得第三方网站的授权,注意是第三方,而不是在客户端上直接输入第三方网站的密码来获取授权。access token 在标准里也就说了是一个授权字符串,refresh token 是获取 access token 的字符串,根本没人管你怎么验证。你实现成第三方客户端只要把 114514 填进 access token 发给你就算 Authorized ,refresh token 只要是 1919810 你就返回 114514 都没人管你。

    只不过后面 jwt 等无状态 token 的技术出现了,大家就开始往这个标准上套,然后总结出一套最佳实践就是无状态 access token+有状态 refresh token ,其中无状态 access token 就可以直接用 jwt 的方式实现(也有不用 jwt 的,google oauth api 就不是 jwt )。这样不管是第一方还是第三方的验证,都可以在无状态和有状态验证的优缺点之间取得一个平衡。还有不少人其实连 oauth 2.0 一开始是给第三方授权的都不知道,第一方授权也这么写,然后不知道这标准为什么要这么定义,就去硬套说什么给用户无感刷新用,这就是为了凑个理由强行说了。你第一方对自己的客户端,直接把 refreshtoken 做成 jwt 一直无状态也没人管你,反正发行 token 的时候用户肯定要敲账号密码的,账号密码也都存在你这里,谁来管你呢?
    urlk
        31
    urlk  
       2 小时 49 分钟前
    jwt 本质上只是把用户 id 进行编码,加上域名用于验证,加上过期时间用于判断是否可用 主要信息传的还是用户 id

    jwt 优于 cookie 和 session 的点在于 后者受限于浏览器机制限制,对同源策略不友好,在 app 等非浏览器环境下适配性更好, 在微服务架构中网关处理更加方便, 安全方面由于不在 cookie 中传输,所以天然防御 CSRF 攻击

    单 jwt Token 续签流程,用的就是短过期时间 例如 30 分钟 + 长过期时间标记 例如 7 天, 当短过期时间过期: 拒绝请求,返回过期错误,要求前端用旧 Token 请求刷新接口, 长过期时间过期 则返回 401 要求重新登陆

    至于 Refresh Token 刷新令牌是 OAuth 2.0 授权框架中的概念, 使用 Refresh Token 长有效期刷新 Access Token 短有效期, 比单 Token 机制更加安全
    catamaran
        32
    catamaran  
       2 小时 48 分钟前
    客户要求登出后 token 必须失效,直接又把 jwt 扔 session 里了
    lusxh
        33
    lusxh  
    OP
       2 小时 47 分钟前 via iPhone
    @sentinelK 为了性能,反而丢失了一定时间的安全性
    lusxh
        34
    lusxh  
    OP
       2 小时 43 分钟前 via iPhone
    @sentinelK 中文的博大精深,错误命题,问出来了一大推正确答案。
    lusxh
        35
    lusxh  
    OP
       2 小时 42 分钟前 via iPhone
    @photon006 Refresh Token 到期也面临这个问题么。
    zxjxzj9
        36
    zxjxzj9  
       2 小时 38 分钟前
    @litchinn 答案是其实根本就不需要续签,针对第一方应用的时候,验证信息(账号密码 passkey 等)全都保存在第一方后端里,发行任何 token 都需要完整信息验证,这种情况下是续签是为了续签而续签(降低数据库访问),是实际操作上的处理,而并非 refresh token 设计出来的本意。oauth 2.0 之所以设置成两个 token ,是因为标准上来说,oauth2.0 希望客户端无法知道第三方给的 access token 内部的具体细节,而给了 refresh token 就相当于第三方信任了当前客户端,并且留了一手可以随时撤销授权的能力。 在进行授权操作的时候,第三方完全可以不给 refresh token ,只给 access token (比方说第三方登录的时候只给一个 access token 来让当前客户端拿到用户名,不给继续访问后续信息的权限)。
    lusxh
        37
    lusxh  
    OP
       2 小时 20 分钟前 via iPhone
    @zxjxzj9 大家看看这老哥的答案。我也感觉,我自己写的系统为什么要用双 token ,没感觉双 token 那里好么,下次面试碰到这种问题,就这么回答了。
    billbur
        38
    billbur  
       2 小时 13 分钟前
    我对双 token 的理解比较粗浅,用途上 access token 是给一个相对较短有效期的授权,而 refresh token 则是用来续签的,有效期较长,给受信任的客户端环境才签发。在 access token 有效期内无需重新登录,在 refresh token 有效期内无感续签,比如本次登录没勾选保持登录状态,access token 可在本次会话中一直使用只要你别关闭浏览器,关闭标签页重新开个网页依旧是登录状态的;如果登录时勾选了保持登录状态,那么 refresh token 应该是持久化保存的,重开浏览器什么的依旧可以维持登录状态,因为你的客户端可以拿 refresh token 去重新签一个 access token 。而超过 refresh token 有效期了则强制要求登录一次验证身份,这是一种很简单的安全手段。至于数据库存不存查不查那实际上是看会话管理上需不需要,实际上可以不要的
    shakaraka
        39
    shakaraka  
    PRO
       2 小时 12 分钟前
    @lusxh #37

    90%的场景,把 session 丢 header 即可。什么 jwt 来的都不需要
    lusxh
        40
    lusxh  
    OP
       1 小时 52 分钟前 via iPhone
    @billbur 确实粗浅
    billbur
        41
    billbur  
       1 小时 49 分钟前
    @lusxh #40 对的,因为我觉得根本不需要把问题复杂化,把问题简单化才能更好的避免引发各种问题,当然这是我个人的经验之谈,不是什么正解
    realpg
        42
    realpg  
    PRO
       53 分钟前
    我给你举个不恰当的方便理解的例子.

    有一个系统, 他的安全等级较高, 采用了天顶星科技都无法破解的加解密系统存储用户名, 采用了天顶星科技的都无法创建碰撞的 hash 算法存储密码

    一次加解密用户名开销要 30 秒, 一次 hash 开销要 5 秒

    这时候,不用 refresh token 和用 refresh token 的性能差异就非常明显了...


    然后这只是极端情况, 但是所需计算性能的维度因素是可以转换的

    现实中你可能并没有这种加密要 30 秒的算法, 但是你可能有 10 亿活跃并发请求, 照样压死算法执行器
    teric
        43
    teric  
       46 分钟前
    如果不用双 token,你准备让你的单 token 多久失效,如果你有多个系统需要鉴权,如果这时候要控制用户访问,这时候单 token 应该怎么做?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4950 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 09:34 PVG 17:34 LAX 01:34 JFK 04:34
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86