# Token 鉴权

2022年8月31日7分钟阅读

- FormalSciences/ComputerScience
- ComputerSecurity/UserSecurity

## Token 鉴权

现在我们已经得知，Session-Cookie 的一些缺点，以及 Session 的维护给服务端造成很大困扰，我们必须找地方存放它，又要考虑分布式的问题，甚至要单独为了它启用一套 Redis 集群。那有没有更好的办法？

于是 Token 就应运而生了

### Token（令牌）

Token 是一个令牌，客户端访问服务器时，验证通过后服务端会为其签发一张令牌，之后，客户端就可以携带令牌访问服务器，服务端只需要验证令牌的有效性即可。一句话概括：访问资源接口（API）时所需要的资源凭证

#### Token 的组成

一般 Token 的组成由 uid （用户唯一的身份标识）+ time（当前时间的时间戳) + sign （签名，Token 的前几位以哈希算法压缩成的一定长度的十六进制字符串）

#### Token 的认证流程图

#### Token 认证步骤解析

1. 客户端： 输入用户名和密码请求登录校验。
2. 服务器： 收到请求验证用户名与密码；验证成功后，服务端会签发一个 Token，并把这个 Token 发送给客户端。
3. 客户端： 收到 Token 以后需要把它存储起来，Web 端一般会放在 localStorage 或 Cookie 中，移动端原生 APP 一般存储在本地缓存中。
4. 客户端： 再次向服务端请求 API 资源的时候，将 Token 通过 HTTP 请求头 Authorization 字段或者其它方式发送给服务端。
5. 服务器： 收到请求，然后去验证客户端请求里面带着的 Token ，如果验证成功，就向客户端返回请求的数据，否则拒绝返还（401）。

#### Token 的优点

- 服务端无状态化、可扩展性好： Token 机制在服务端不需要存储会话（Session）信息，因为 Token 自身包含了其所标识用户的相关信息，这有利于在多个服务间共享用户状态。
- 支持 APP 移动端设备。
- 安全性好： 有效避免 CSRF 攻击（因为不需要 Cookie）。
- 支持跨程序调用： 因为 Cookie 是不允许跨域访问的，而 Token 则不存在这个问题。

#### Token 的缺点

- 配合： 需要前后端配合处理。
- 占带宽： 正常情况下比 sid 更大，消耗更多流量，挤占更多宽带。
- 性能问题： 虽说验证 Token 时不用再去访问数据库或远程服务进行权限校验，但是需要对 Token 加解密等操作，所以会更耗性能。
- 有效期短： 为了避免 Token 被盗用，一般 Token 的有效期会设置的较短，所以就有了 Refresh Token。

### Refresh Token（刷新 Token）

业务接口用来鉴权的 Token，我们称之为 Access Token。为了安全，我们的 Access Token 有效期一般设置较短，以避免被盗用。但过短的有效期会造成 Access Token 经常过期，过期后怎么办呢？

一种办法是刷新 Access Token，让用户重新登录获取新 Token，会很麻烦。另一种办法是再来一个 Token，一个专门生成 Access Token 的 Token，我们称为 Refresh Token。

- Access Token： 用来访问业务接口，由于有效期足够短，盗用风险小，也可以使请求方式更宽松灵活；
- Refresh Token： 用来获取 Access Token，有效期可以长一些，通过独立服务和严格的请求方式增加安全性；由于不常验证，也可以如前面的 Session 一样处理；

#### Refresh Token 的认证流程图

#### Refresh Token 认证步骤解析

1. 客户端： 输入用户名和密码请求登录校验。
2. 服务端： 收到请求，验证用户名与密码；验证成功后，服务端会签发一个 Access Token 和 Refresh Token 并返回给客户端；
3. 客户端： 把 Access Token 和 Refresh Token 存储在本地；
4. 客户端： 请求数据时，携带 Access Token 传输给服务端；
5. 服务端：
   - 验证 Access Token 有效：正常返回数据
   - 验证 Access Token 过期：拒绝请求
6. 客户端 ( Access Token 已过期) ： 则重新传输 Refresh Token 给服务端；
7. 服务端 ( Access Token 已过期) ： 验证 Refresh Token ，验证成功后返回新的 Access Token 给客户端；
8. 客户端： 重新携带新的 Access Token 请求接口；

### Token 和 Session-Cookie 的区别

Session-Cookie 和 Token 有很多类似的地方，但是 Token 更像是 Session-Cookie 的升级改良版。

- 存储地不同： Session 一般是存储在服务端；Token 是无状态的，一般由前端存储。
- 安全性不同： Session 和 Token 并不矛盾，作为身份认证 Token 安全性比 Session 好，因为每一个请求都有签名还能防止监听以及重放攻击。
- 支持性不同： Session-Cookie 认证需要靠浏览器的 Cookie 机制实现，如果遇到原生 NativeAPP 时这种机制就不起作用了，或是浏览器的 Cookie 存储功能被禁用，也是无法使用该认证机制实现鉴权的；而 Token 验证机制丰富了客户端类型。