对 Token 的思考

date
Aug 24, 2020
slug
iabxiusk
status
Published
tags
业务
summary
type
Post
 
阅读本文之前,推荐先阅读下面文章:
如上面文章里提到,帐号体系已经成为一个互联网产品的必备基石,往往是一个服务器(或单独的账户服务器),N 个客户端的架构。
notion image
20200425
下面重点说说 Token、JWT 的区别:
相同:
  • 都是访问资源的令牌
  • 都可以记录用户的信息
  • 都是使服务端无状态化
  • 都是只有验证成功后,客户端才能访问服务端上受保护的资源
区别:
  • Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证 Token 是否有效。
  • JWT:将 Token 和 Payload 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。
常见的前后端鉴权方式:
  • Session-Cookie:前后端分离后,使用频率大幅降低;
  • Token 验证(包括 JWT,SSO):中小型项目中常用;
  • OAuth2.0(开放授权):中大型项目中常用,特别是会对外开放的服务;

OAuth2.0

笔者推荐 OAuth2.0,该模型设计成熟,应用广泛,对后端来说有很多现成的第三方包,降低了接入难度。
一般情况下,access_token 有效期较短,refresh_token 拥有较长的有效期(如一个月、一年等)。而且第三方平台的响应字段里没有 refresh_token 的过期时间,需关注文档,自己记录 refresh_token 的过期时间。
另外,不同开发平台对 refresh_token 管理不一样,如:豆瓣网、百度云,refresh_token 仅能使用一次,因此当用 refresh_token 更新 access_token 后,会返回一个新的 refresh_token。
下面摘自微信的开发文档:
{    "access_token":"ACCESS_TOKEN",    "expires_in":7200,    "refresh_token":"REFRESH_TOKEN",    "openid":"OPENID",    "scope":"SCOPE",    "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"}
1、刷新 access_token 有效期 access_token 是调用授权关系接口的调用凭证,由于 access_token 有效期(目前为 2 个小时)较短,当 access_token 超时后,可以使用 refresh_token 进行刷新,access_token 刷新结果有两种:
  • 若 access_token 已超时,那么进行 refresh_token 会获取一个新的 access_token,新的超时时间;
  • 若 access_token 未超时,那么进行 refresh_token 不会改变 access_token,但超时时间会刷新,相当于续期 access_token。
2、refresh_token 拥有较长的有效期(30 天),当 refresh_token 失效的后,需要用户重新授权。
所以正确的登录流程应该是:(以 refresh_token 有效期 30 天、access_token 有效期 2 小时为例)
  1. 判断是否有 refresh_token 的时间缓存:
    1. 若无,执行登录流程。
    2. 若有,则判断 refresh_token 是否过期。 if 当前时间 - 缓存时间戳 >= 30,说明 refresh_token 已过期,则重新登录。
  1. 若 refresh_token 没有过期,走判断 access_token 是否过期:
    1. 读取 expire_date,判断 access_token 是否过期。 if 当前时间 - expire_date > 2 小时,说明已经过期,需要去获取新的 access_token 和 expire_date,把结果缓存到本地。
    2. 若 access_token 没有过期,走调用接口流程。
  1. 利用有效的 access_token,进行接口请求,获取不同业务场景数据。
对前端来说,就要思考下面几个问题:
  • 执行业务请求时,access_token 失效,自动执行 refresh_token,携带最新 access_token 重试之前的业务请求;
  • 多业务请求并发访问时,所有请求均失效,保证仅有一次 refresh_token 操作;
  • 对 refresh_token 进行合理的节流;
  • 业务请求+refresh_token 合理的降级策略;
  • 特殊场景:no refresh_token 白名单策略、单点在线业务;
简单的说,当 access_token 失效时,要自动刷新 access_token,并且不能影响正常业务请求,而且要考虑并发刷新的问题。
分析前面的登录流程,发现有 2 个时间点是可以调整的,那我们是不是可以改变时间点,来降低因 token 临近过期而引起的程序健壮问题呢?比如现实中 90%以上用户会在 01:00~04:00 期间睡觉为例,那么一个 app、web 页面等常驻前台不会超过 1 天的:
  • refresh_token 过期判断,由>= 30 改为 >= 28
  • access_token 过期由固定2小时 改为 变长时间差(第二天凌晨三点 - 当前时间时间)
在如 IM 等可能存在会限制单点在线的业务里,这是单 token 模式(不限制有效期)会更合适,因为 IM 往往是长连接模式,而且服务器会记录每个登录设备会记录唯一 ID,token 失效后服务器会主动通知客户端。

Token 在访客模式中的应用

  1. 防止爬虫和机器人,下面摘自API 接口设计中 Token 设计讨论
    1. notion image
      * 其中签名的算法中的{Session}是通过加密的信息,用于判断当前 页面的请求。
      * {浏览器摘要}中会记录访问者的ip及浏览器信息,用于防止token被不同的机器使用
      
      使用场景:
      * 媒体临时访问页面,用于防止机器爬虫获取token后无限访问其他界面
      * 动态临时界面,防止机器不断获取动态临时页面信息中的数据
  1. 访客模式下的用户行为如何转移到登录用户下 在某个电商产品里,用户小明在访客模式下使用了该产品一段时间,比如搜索了自行车、笔记本电脑等商品,突然某一天注册并登录了产品,这时就需要把之前的浏览器数据关联到小明的账户下,以便后台给小明继续推荐他感兴趣的商品。
参考资料:

© 刘德华 2020 - 2023