Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。
为什么要用 Token?
- Token 完全由应用管理,所以它可以避开同源策略。
- Token 可以避免 CSRF 攻击(http://dwz.cn/7joLzx)。
- Token 可以是无状态的,可以在多个服务间共享。
- Token 是在服务端产生的,如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。
- 前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。
要为 Token 设置有效期吗?
中华人民共和国身份证还有期限呢....
先看两个例子:
- 安全角度
- 吊销角度
有效期多长合适呢?
只能说,根据系统的安全需要,尽可能的短,但也不能短得离谱。
- 想像一下手机的自动熄屏时间,如果设置为 10 秒钟无操作自动熄屏,再次点亮需要输入密码,会不会疯?
- 新问题产生了,如果用户在正常操作的过程中,Token 过期失效了,要求用户重新登录……用户体验岂不是很糟糕?
解决在操作过程不能让用户感到 Token 失效问题
- 在服务器端保存 Token 状态,用户每次操作都会自动刷新(推迟) Token 的过期时间——Session 就是采用这种策略来保持用户登录状态的。
- 存在这样一个问题,在前后端分离、单页 App 这些情况下,每秒种可能发起很多次请求,每次都去刷新过期时间会产生非常大的代价。
- 如果 Token 的过期时间被持久化到数据库或文件,代价就更大了。
- 所以通常为了提升效率,减少消耗,会把 Token 的过期时保存在缓存或者内存中
- 另一种方案,使用 Refresh Token,它可以
避免频繁的读写操作。这种方案中,服务端不需要刷新 Token 的过期时间,一旦 Token 过期,就反馈给前端,前端使用 Refresh Token 申请一个全新 Token 继续使用。
- 这种方案中,服务端只需要在客户端请求更新 Token 的时候对 Refresh Token 的有效性进行一次检查,大大减少了更新有效期的操作,也就避免了频繁读写。
当然 Refresh Token 也是有有效期的,但是这个有效期就可以长一点了,比如,以天为单位的时间。
时序图表示
使用 Token 和 Refresh Token 的时序图如下:
- 登录
- 业务请求
- Token 过期,刷新 Token
Refresh Token 过期怎么办
- 显然,Refresh Token 既然已经过期,就该要求用户重新登录了。
- 当然还可以把这个机制设计得更复杂一些。比如,Refresh Token 每次使用的时候,都更新它的过期时间,直到与它的创建时间相比,已经超过了非常长的一段时间(比如三个月),这等于是在相当长一段时间内允许 Refresh Token 自动续期。
到目前为止,Token 都是有状态的,即在服务端需要保存并记录相关属性那说好的无状态呢,怎么实现?
无状态 Token
- 如果我们把所有状态信息都附加在 Token 上,服务器就可以不保存。但是服务端仍然需要认证 Token 有效。
- 不过只要服务端能确认是自己签发的 Token,而且其信息未被改动过,那就可以认为 Token 有效——“签名”可以作此保证。
平时常说的签名都存在一方签发,另一方验证的情况,所以要使用非对称加密算法。
但是在这里,签发和验证都是同一方,所以对称加密算法就能达到要求,而对称算法比非对称算法要快得多(可达数十倍差距)。