状态管理
有/无状态协议
1. 协议状态
七层网络协议,大多都是有状态协议,如 SMTP ,但 HTTP 协议,则是无状态协议
1.1 有状态协议
如 SMTP 协议
- 发送前必须先建立 TCP 连接,并发送 HELO/EHLO 建立会话
- 然后进入 AUTH 认证
- 认证通过才可以发送数据
- 通过 QUI 命令关闭会话
如上,整个通信过程,双方是必须要时刻记住当前连接的状态的,不同状态能接受的命令是不同的。另外,之前命令传输的某些数据也必须要记住,因为可能会对后续的命令产生影响
这种有记忆功能的,就是有状态协议,通常维护状态代价较高
1.2 HTTP1.X 无状态协议
指协议对于交互性场景,没有记忆能力
- 每个请求(交互)都是独立的,本次请求不会基于上次请求有任何改变
- 比如:用户登录,和把东西加入购物车,HTTP 不会去记录谁 和 他干了什么,是 完全无依赖 的
- 没有记忆能力,即无存储
- 因此需要外部、如 Cookie、Session 等为交互存储状态
- 和 TCP/IP 不同,发过去就断开了
- 减少服务器的 CPU 和 内存 开销
2. Cookie
英文翻译为 甜品,使用 Cookie 可自动填写用户名、记住密码等,算是给用户的一点甜头
3. Session
因为存入 Cookie,有泄密风险,因此将机密信息存入服务器,通过服务器来维护客户档案
- 可以理解为服务端存储了一张 User 表, SessionID 即该表主键
- 占用服务器资源,用户都要去 Session 服务器授权,因此限制负载均衡能力
- 可以CSRF 跨域伪造请求,依然泄密
4. Token
令牌鉴权,不存用户信息了,采用不同的加密方式进行数字签名
- 用户访问服务器去到加密后的令牌,后续访问直接使用令牌即可
- 哪怕下次访问负载均衡的其他节点,也可以根据令牌进行鉴权
- 坏处是依然需要查库(去数据库查询认证信息,进行鉴权)
因此为了服务器不存储、不查库、能鉴权,诞生了如今的 JWT
5. JWT
时下最流行的跨域认证解决方案
JWT 全称 JSON Web Token 它可以将所有信息都以 JSON 格式存储,包括 用户名、密码、加密信息等
5.1 组成部分
通常由三部分组成,它们之间用圆点 .
连接
Header: 两部分组成,包括 token 类型 & 加密算法(HMAC SHA256 或者 RSA)
{ "alg": "HS256", "typ": "JWT" }
Payload: 包含声明,指关于用户和其他数据的声明,存放实际传递的数据,有三种类型:
- Registered claims: 预定义声明,非强制,如:iss (issuer), exp (expiration time), sub (subject), aud (audience) 等
- Public claims: 可随意定义
- Private claims: 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明
{ "sub": "1234567890", "name": "john", "admin": true }
对 payload 进行 Base64 编码就会得到 JWT 的第二部分
注意: 不要在 payload 或 header 中放置敏感信息,因为默认是不加密的
Signature: 对上面两部分的签名,防止消息被篡改
需要指定一个只有服务器知道的密钥(secret )不能泄露给用户,然后按照如下形式生成签名
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
5.2 JWT 使用方式
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 LocalStorage
此后,客户端每次与服务器通信,都要带上这个 JWT
可把它放在 Cookie 里自动发送,但这样不能跨域。更好的做法是放 HTTP 请求头 的 Authorization字段里
Authorization: Bearer <token>
另一种是,跨域的时候,JWT 就放在 POST 请求的数据体里面