在技术网站看到过无数次前端无感刷新 token 的文章,一直很费解,为啥要刷新 token 呢?那前端给 token 刷新了,token 还有啥意义呢?

文章给出的原因是,用户正操作着呢,token 突然过期,跳登录页用户体验不好。

实现步骤:
accessToken 简称 at ,refreshToken 简称 rt

  1. rt 有效期长,at 有效期短
  2. at 过期了拿 rt 换 at ,重新请求

疑问:

  1. 既然 rt 长期有效,直接用 rt 有啥问题
  2. 如果从安全考虑,rt 被抓包拿了,也没辙呀
  3. 既然后端知道用户操作了,如果是非异常操作,就自动给 token 延时行不?

不知道该方案具体是为了什么,还请大神们赐教。希望接到类似需求老哥们聊聊

PS:轻喷,心平气和

感觉大家的解答,目前出现了两个能说服我的理由(也是自己总结,不知对错,可以修正)

  1. rt 无法访问资源服务器,at 无法访问用户服务器,给抓包、攻击提高了复杂度
  2. 资源服务器可以直接解析 at ,仅在 at 过期后才访问用户服务器,缓解了用户服务器的压力

产生了新的疑问:
有几位提到了 at 不可修改,所以一般有效期设置的较短,那么

  1. 当用户修改了账号密码时,会主动通知资源服务器 at 过期了吗?
  2. 我不知道 1 的答案,所以先假设不通知,那该怎么办呢?

    我觉得只是增加抓包难度罢了,提升用户体验只是带来的"副作用",
    安全不安全,主要看你项目有没有真金白银的价值,有的话,管你啥 refresh_token 还是啥,分分钟给你抓出来

    这么一说确实有道理的,小厂反正无所谓怎么搞都行。大厂的话我的理解就是 refreshToken 可以多一道控制,accessToken 签出之后无法控制失效(除非加黑名单),但 refreshToken 可以控制下一次 accessToken

    这一切的前提是 HTTPS.
    如果有 HTTPS.可以保证你只会被重放攻击.不会真正泄漏 token 的值.

1.小项目这样做没问题. 只不过如果 rt 可以请求资源. 那就是说可能会被一直重放攻击. 如果 rt 只能换 at.at 过期了.他就不能重放了(他得再次抓包). 安全一丢丢.
2.基于前提.rt 不会被获取值的.
3.可行但怪麻烦的,不如直接用长期 token

个人的理解.不一定完全正确.

refreshToken 不能访问资源啊

accessToken 有效期短一点,相对安全一点

我以前碰到的时候思考的,不一定对:“服务器端校验 refreshtoken 消耗的资源比 accesstoken 大。”
更深的原因就没有细究了。

我也无法理解为啥要 jwt ,短短的 token 不香吗

Access Token 可能是 JWT, 服务端收到时可以通过校验签名来确认是否有效, 不一定需要查询数据库或做完整的校验. JWT 弊端是签出后无法轻松控制失效, 所以需要 Refresh Token 来弥补.

我理解的每个请求都有 access_token 的传递,但是只有登录、刷新 token 等操作才会传递 refresh_token ,这样的话 refresh_token 被抓包的几率小多了,然后 access_token 泄露的话那么下次过期自然被抓包的那次就不能再使用了

2 、rt 一般会存数据库,所以有办法踢,at 可以接受不能踢,有效期可以很短

https 不能重发的。高版本 tls 如果没对握手信息做记录,会话结束后,你拿着私钥都没法把流量解密。更不要说重放了。
这种我理解更多还是防 XSS 。

  1. refreshToken 不应该能访问资源服务器,简单来说 RT 和 AT 访问的“服务器”都是不一样的。
  1. 这是防中间人的问题,跟是否使用 RT&AT 方案无关,这是 HTTPS 等方案的事。
  2. 不行,跟 1 同理,AT 和 RT 是访问不同服务器的钥匙,你有 AT 不代表你有 RT ;抛开权限不同这点,如果后端实现了自动刷新,那就相当于 AT 和 RT 合一,又回到了单一 token 的方案了。

延伸谈一下,AT&RT 与单 Token 的方案最大的区别是把“获取授权”跟“获取资源”两个行为彻底分离,前者是一个高危害低频率的行为,后者是一个低危害高频率的行为(这里的危害是指 Token 泄漏后带来的影响);越高频率就意味着越高的暴露风险,所以对于高危害的行为,单独出来放在一个低出现频率的 Token 能提高安全性。

不负责任的盲猜一下,没有开发经验纯盲猜啊

弄个有效期短的临时 ak ,对热缓存和集群部署更友好,token 表直接放内存里面弄个 kv cache 查,肯定比每次请求查用户表去校验 ak ,性能更高一点,只有 refresh token 换 ak 的时候,才需要查一下用户表,验证一下 refresh token 是否有效。

放弃 jwt 直接全部服务器存状态吧。

这玩意是用来单点登录的
双 token 方案既减轻了服务器压力,又对用户的登录态具有一定的控制,其实是个折中的方案

换句话说,就是用 RT 代替了账号密码,如果每次请求都携带账号密码,则暴露的风险更高

看看腾讯云,token 过期,直接弹窗登录就好了,不用跳到登录页面

at:一般是 jwt ,无状态服务颁发后后端无法控制,而且承载实际权限,所以为了安全,设计有效时间一般较短
rt:at 有效期短势必需要刷新了,那么刷新 ak 有哪些方案可选?:

  1. at 刷新 at:那我还不如直接长有效时间 at ,安全考虑,不成立;
  2. username/password 刷新 at:username/password 手动输入体验就差,存放在 local-stroage 又太危险了;
  3. rt:折中方案

这个是一个折中方案,jwt 是无状态的嘛,如果签了一个很长的 at,那么这个用户就无法控制( ban )了。但是有个 rt ,那么类似于多久让前端主动请求一下用户状态。

增加操作空间吧,如果后端什么监控和防护措施都没有,那就是脱裤子放屁,去你所说 rt 被抓包了等于密码泄露。但是如果加了防护措施可以规避异常访问,用的来说就是在用户体验与安全性的折中做法。。

错别字: 如你所说、总的来说

以前应该很香,现在看应该算是裹脚布 又长又臭

这是为了缓解 OAuth2 在实际应用中的一个主要缺陷,通常访问令牌一旦发放,除非超过了令牌中的有效期,否则很难(需要付出较大代价)有其他方式让它失效,所以访问令牌的时效性一般设计的比较短,譬如几个小时,如果还需要继续用,那就定期用刷新令牌去更新,授权服务器就可以在更新过程中决定是否还要继续给予授权。 -- 凤凰架构

accessToken 、refreshToken 双 Token 只在分布式|微服务架构下有意义。

考虑我们有用户微服务和订单微服务,我们把用户信息存储在用户微服务,向订单微服务发起请求时需要验证用户有效性:

  1. 如果使用单 token 方案,订单微服务接到请求时 需要向用户微服务发起询问来验证用户有效性,在这一步至少需要一次网络通信。
  2. 如果使用双 token 方案,向用户微服务发起请求时携带 refreshToken ,向订单微服务发起请求时携带 accessToken ,accessToken 过期时向用户微服务发起请求重写签发 accessToken 。
    accessToken 具有以下特性:
    · 明文:这允许订单微服务直接从 accessToken 读取用户信息而不必询问用户微服务;
    · 具备签名:这允许订单微服务直接验证 accessToken 的有效性而不必询问用户微服务;
    · 不可篡改:这使得 accessToken 一经用户微服务签发则在有效期内一直有效,当用户更改密码或其他需要重制登录状态的时候 accessToken 也不受影响,为了满足重制登录状态的需求 accessToken 的有效期一般比较短。
    总结一下,双 token 方案使得订单微服务微服务不用向用户微服务发起询问,代价是 accessToken 不可篡改、登录状态难以清除。

回答楼主的问题:

  1. refreshToken 只能向用户微服务发起请求,订单微服务无法验证 refreshToken 的有效性;
  2. 是的;
  3. accessToken 不可篡改,不可延时;

个人看法:双 token 方案带来的「无需向认证服务询问」的特性有一点点优势;但很多场景会有下「踢出用户」的需求,这时候使用双 token 要么等着 accessToken 过期,要么向认证服务发起询问,前者实时性低,后者让损失了 双 token 方案唯一的优势。我的建议是摒弃双 token 方案,使用单 token 存 redis ,认证服务和业务服务都直接从 redis 读取用户状态。

讲真, 我觉得还不如那个脱裤子放屁的操作: 加一道 redis 检验, 判断应该 401 还是正常使用, 既使用了 jwt 的简单粗暴, 又成功把部分数据库压力转移到内存去.

这个话题展开讲的话内容太多了,简单说就是一切还是要回归到你的业务需求上,rt 存在本身肯定是有意义的

安全性考虑,在 JWT 场景,at 有效期不能太久,因为无法踢掉。rt 重新签发,能做一些安全校验。

去年实习的时候有在掘金提过类似的问题,也是关于双 token 的意义的。实习公司做的小项目也要上双 token ,到现在仍旧没有一个能够彻底说服我的理由。

类 JWT 场景下,at 是用签名来验证,而不用实际比对数据库。当发生某些需要 revoke token 的场景时,如果 at 的有效期足够短,可以不实现。等到过期校验 rt 时,发现不可用了,再进行退出。

所有用无限期的 token 的时候都一定有过临时 token 。比如后台某个服务/脚本临时用个 token 。。然后时间长了,这个 token 就无法改了,特别的蛋疼。token 就应该是无状态的,一定时间内轮换。不然请用 cookie/session 机制。

另一方面。我就在我之前公司 app 上碰到过。无聊的黑客,登陆了就拿着 token 无限制的做任何事。等你发现的时候已经受损失了。如果是双 token 机制,上线的时候就会把访问频率考虑进去。单 token 的,大部分程序员应该实现的就是又不是不能用策略。。防刷?想啥呢。。。

纯粹就是为了性能,和安全性/分布式什么的一点关系都没有。
at 是离线校验,不读数据库。
rt 是在线校验,需要访问数据库。
假设某种业务每个小时访问接口 1000 次,at 有效期 1 个小时。此时每个小时可以省 999 次访问数据库。只有过期的那次才需要刷一下

针对新的疑问:

  1. 不通知;
  2. 只能等待过期,所以才设计较短的有效期来一定程度上规避安全风险。

    看到一个银行的实现,accessToken 有效期 2 分钟

    小业务规模上,直接签一年的

    refreshToken 我的看法是只是给 jwt 打个补丁,jwt 这东西它就不适合用来做用户登录。用户登录还是老老实实用 session 吧。

    鉴权方案有很多种,JWT 属于很辣鸡的那类。云厂商喜欢用 api_key 标识账户,api_secret 对参数签名,生成一次性的 token

    acessToken 用来感知用户是否在线

    jwt 只是鉴权方案的一种形式,也不一定要用。

    无意义,直接用服务端 token ,jwt 只适合一次性授权

    tls + cookie 不香吗

    refreshToken ,认证应该可以结合一些签名、特征校验吧,比如 refreshToken 只在一台设备、一个地址生效?

    为了假装自己的系统很有价值会被人挟持 token