2022-08-31 15:59:07 +08:00
|
|
|
|
---
|
|
|
|
|
title: Token 鉴权
|
|
|
|
|
description: Token 鉴权
|
|
|
|
|
keywords:
|
2023-11-09 17:30:33 +08:00
|
|
|
|
- Token
|
|
|
|
|
- 鉴权
|
2022-08-31 15:59:07 +08:00
|
|
|
|
tags:
|
2024-10-14 16:48:38 +08:00
|
|
|
|
- FormalSciences/ComputerScience
|
|
|
|
|
- ComputerSecurity/UserSecurity
|
2022-08-31 15:59:07 +08:00
|
|
|
|
author: 7Wate
|
|
|
|
|
date: 2022-08-31
|
|
|
|
|
---
|
2023-11-09 17:30:33 +08:00
|
|
|
|
|
2022-08-31 15:59:07 +08:00
|
|
|
|
## Token 鉴权
|
|
|
|
|
|
|
|
|
|
现在我们已经得知,Session-Cookie 的一些缺点,以及 Session 的维护给服务端造成很大困扰,我们必须找地方存放它,又要考虑分布式的问题,甚至要单独为了它启用一套 Redis 集群。那有没有更好的办法?
|
|
|
|
|
|
|
|
|
|
于是 Token 就应运而生了
|
|
|
|
|
|
|
|
|
|
### Token(令牌)
|
|
|
|
|
|
|
|
|
|
Token 是一个令牌,客户端访问服务器时,验证通过后服务端会为其签发一张令牌,之后,客户端就可以携带令牌访问服务器,服务端只需要验证令牌的有效性即可。一句话概括:**访问资源接口(API)时所需要的资源凭证**
|
|
|
|
|
|
|
|
|
|
#### Token 的组成
|
|
|
|
|
|
|
|
|
|
一般 Token 的组成由 **uid** (用户唯一的身份标识)+ **time**(当前时间的时间戳) + **sign** (签名,Token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
|
|
|
|
|
|
|
|
|
|
#### Token 的认证流程图
|
|
|
|
|
|
|
|
|
|
![Token 的认证流程图](https://static.7wate.com/img/2022/08/30/40b2dbfe8f84a.png)
|
|
|
|
|
|
|
|
|
|
#### 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 的缺点
|
|
|
|
|
|
|
|
|
|
- **配合:** 需要前后端配合处理。
|
2023-11-09 17:30:33 +08:00
|
|
|
|
- **占带宽:** 正常情况下比 sid 更大,消耗更多流量,挤占更多宽带。
|
2022-08-31 15:59:07 +08:00
|
|
|
|
- **性能问题:** 虽说验证 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 的认证流程图](https://static.7wate.com/img/2022/08/30/0f634bdff18ca.png)
|
|
|
|
|
|
|
|
|
|
#### 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 验证机制丰富了客户端类型。
|