对 Token 的思考
date
Aug 24, 2020
slug
iabxiusk
status
Published
tags
业务
summary
type
Post
阅读本文之前,推荐先阅读下面文章:
如上面文章里提到,帐号体系已经成为一个互联网产品的必备基石,往往是一个服务器(或单独的账户服务器),N 个客户端的架构。
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 小时为例)
- 判断是否有 refresh_token 的时间缓存:
- 若无,执行登录流程。
- 若有,则判断 refresh_token 是否过期。 if 当前时间 - 缓存时间戳 >= 30,说明 refresh_token 已过期,则重新登录。
- 若 refresh_token 没有过期,走判断 access_token 是否过期:
- 读取 expire_date,判断 access_token 是否过期。 if 当前时间 - expire_date > 2 小时,说明已经过期,需要去获取新的 access_token 和 expire_date,把结果缓存到本地。
- 若 access_token 没有过期,走调用接口流程。
- 利用有效的 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 在访客模式中的应用
- 防止爬虫和机器人,下面摘自API 接口设计中 Token 设计讨论:
* 其中签名的算法中的{Session}是通过加密的信息,用于判断当前 页面的请求。
* {浏览器摘要}中会记录访问者的ip及浏览器信息,用于防止token被不同的机器使用
使用场景:
* 媒体临时访问页面,用于防止机器爬虫获取token后无限访问其他界面
* 动态临时界面,防止机器不断获取动态临时页面信息中的数据
- 访客模式下的用户行为如何转移到登录用户下 在某个电商产品里,用户小明在访客模式下使用了该产品一段时间,比如搜索了自行车、笔记本电脑等商品,突然某一天注册并登录了产品,这时就需要把之前的浏览器数据关联到小明的账户下,以便后台给小明继续推荐他感兴趣的商品。
参考资料: