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

Token 的自动续订,过期时间,常用设备登录的方案

  •  2
     
  •   cp19890714 · 122 天前 · 1984 次点击
    这是一个创建于 122 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在使用 Token 做登录身份. 自己尝试了一些方案, 但是感觉都不完美, baidu/google 也都没有找到好方案. 所以提出来, 请各位指点下.

    token 自动续订

    token 自动续订, 是为了保证用户在使用系统的过程中,自动刷新 accessToken,用户无感知,不会被要求强制登录.

    • 前端被动刷新

    请求响应 401 且 accesstoken 无效时,refreshToken retry.

    为了防止并发, 前端需要双重判断加锁, 保证同时有多个请求时, 只会获得一个 AccessToken.

    • 前端定时刷新

    定时检查 token 有效期, 当 token 有效期低于阈值,且用户在最近一定时间内操作过页面, 就 refreshToken.

    refreshToken 的临界点,可能会有并发的业务请求使用 旧的 accessToken, 导致请求失败. 所以在 refreshToken 时,不能立即删除旧的 accessToken,而是 10 秒后过期(删除).

    • 后端刷新

    后端使用 filter, 如果 accessToken 校验失败, 则使用 refreshToken 刷新 accessToken, 并 set-cookie.

    refreshToken 的临界点,可能会有并发的业务请求. 如果 refreshToken 允许复用,会导致刷新出多个不同的 accessToken, 如果 refreshToken 不允许复用,会导致其他请求刷新 accessToken 失败.

    为了解决这个问题, 需要在刷新 accessToken 时, 双重判断加锁. 保证同时有多个请求时, 只会生成一个 AccessToken.

    该方案不符合 Oauth2 规范, refreshToken 应该是 client 行为.

    RememberMe

    由于用户需要在个人电脑与公共电脑上切换.为了保护账号安全,个人电脑上,希望有长期 Token, 公共电脑上,应该是短期 Token. 所以需要提供 RememberMe 特性. 我当前使用的方案如下:

    • 如果用户登录时,没有勾选 RememberMe, 则依赖 RefreshToken 的有效性自动续订.
    • 用户登录时,勾选了 RememberMe,则生成 RememberToken,有效期 14 天, 即使 RefreshToken 失效,也可以依靠 RememberToken 进行自动登录.

    另外还有一种方案:

    • 如果用户登录时,没有勾选 RememberMe, 则 clientId = web-common, accessToken 有效期 1 小时, RefreshToken 有效期 2 小时.
    • 用户登录时,勾选了 RememberMe,则 clientId = web-remember, accessToken 有效期 24 小时, RefreshToken 有效期 14 天.

    问题

    有以下问题,各位有什么想法:

    • token 自动续订 和 RememberMe, 是否有其他方案?
    • token 的有效期多久合适? 我看到 github 的有效期是 14 天.
    • google/facebook/github 等公司是如何管理管理 token 的
    12 条回复    2021-08-04 14:12:05 +08:00
    xjoker
        1
    xjoker  
       122 天前
    等一个大佬来指导下 😄
    最近做一个项目也遇到这种问题了
    liuxianzhuo
        2
    liuxianzhuo  
       122 天前
    我是用的第一种和第二种结合的方式
    前端每次请求时在请求拦截器里判断当前 accesstoken 过期时间,当快过期或者已经过期时使用 refreshtoken 获取新的 accesstoken 并锁住新的并发请求,获取到 accesstoken 后解锁并使用新的 accesstoken 访问
    darknoll
        3
    darknoll  
       122 天前
    @liuxianzhuo 前端如何判断当前 accesstoken 过期时间?
    cp19890714
        4
    cp19890714  
    OP
       122 天前
    @darknoll 我当前使用的是 spring security oauth2. 生成 accessToken 时, 会有过期时间 Date, 以及有效时长 Long.
    liuxianzhuo
        5
    liuxianzhuo  
       122 天前
    @darknoll 生成 accesstoken 时后端可以一并吧有效时长传到前端,后端没有传的话也可以手动 base64 解码 token,里面有个字段是过期时间
    sparrww
        6
    sparrww  
       122 天前
    用户量不大不用纠结,直接每次请求服务端 token 续期就行,想怎么控制怎么控制,量大了加配置,何必自己找麻烦。
    777777
        7
    777777  
       122 天前
    用户每请求一次接口,后端就把 token 过期时间重置为 7 天,当用户 7 天没有操作,token 过期,需要重新登录。
    onhao
        8
    onhao  
       122 天前
    if (isset($_GET['renewal'])) {
    $code = $_POST['code'];
    $uid = c2u($code);
    if ($uid) {
    $data['code'] = u2c($uid);
    $data['status'] = 0;

    }
    }
    cp19890714
        9
    cp19890714  
    OP
       122 天前
    @sparrww
    @777777 每次请求都为 token 续期, 有两个问题:
    1. 如果 token 有效时间较短, 如 4 小时, 那么用户需要经常登录.
    2. 如果 token 有效时间较长, 如 14 天, 会导致 token 长期不变, 影响安全.
    sparrww
        10
    sparrww  
       122 天前
    @cp19890714 你没理解我意思,你可以续期为四小时,也可以根据不同用户随时过期,服务端怎么操作设计,不是你说了算吗
    coderwl
        11
    coderwl  
       121 天前
    client 是相对 Oauth server 的,和前后端没关系吧。刷新 token 之前在我们项目里是用户请求的时候判断,如果快过期了,后端续期,返回的 header 里放新的 token,APP 端有对应的 header 处理逻辑,后端异步删除旧 token
    ztechstack
        12
    ztechstack  
       121 天前
    1. 后端刷新的问题在于,前端每次都要 refresh token 进行传递,这样设计 refresh token 的意义在哪里?
    2. 前端刷新统一一套规则,401 统一 redirect 到一个页面进行刷新,如果刷新成功跳转回之前页面,如果刷新失败,跳转登录页面
    remeber me:不 remeber 的不返回 refreshtoken 即可,accesstoken 浏览器关闭失效,最长时间比如 2 个小时。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2120 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:44 · PVG 23:44 · LAX 07:44 · JFK 10:44
    ♥ Do have faith in what you're doing.