在现代 Web 应用中,用户身份认证与状态管理是构建安全、可靠系统的基础。随着前后端分离架构、单页应用(SPA)、移动端 API 调用等场景的普及,Cookie、Session 和 Token 是三种最为常见的身份认证与状态管理机制。下面对三者的基本概念和区别进行分析
Cookie
Cookie 是由 Web 服务器发送到用户浏览器,并保存在客户端本地的一小段文本数据,主要用于在客户端存储会话状态或用户相关信息
HTTP 是无状态协议,每次 HTTP 的请求与响应都是互不关联的。Cookie 就是为了在多次 HTTP 请求与响应中保持状态而出现的机制。当用户多次访问同一网站时,浏览器会自动将 Cookie 通过 HTTP 请求头(通常是 Cookie
字段)回传给服务器,从而使服务端能够识别用户身份、维持登录状态或记录用户行为
Cookie 的简单运行流程如下
sequenceDiagram participant client as 客户端 participant server as 服务端 client ->>+ server:用户首次登录网站 server ->>- client:返回cookie,存放在响应头的Set-Cookie字段中 client ->>+ server:后续访问中在请求头的Cookie字段中携带cookie server ->>- client:返回用户响应
Cookie 中并没有规定存储的内容,因此 Cookie 本质上只是一种状态存储机制。Cookie 存储信息是明文存储,若直接将用户信息存放在 Cookie 中,会非常不安全,因此出现了 Session 和 Token 两种方案来规定 Cookie 中存储的信息,保证安全性
Session
Session 方案的核心是由服务端来维护用户信息。当用户首次登录网站时,服务端为用户的当前会话生成一个 SessionID,用户信息和会话状态存放在服务端,SessionID 通过 Cookie 返回给客户端,用户后续访问时,在 Cookie 中附带 SessionID,服务端即可通过 SessionID 查找到相应的用户信息和会话状态
可以将 SessionID 类比作身份证号,服务端接收到身份证号后需要根据身份证号查询出用户信息
大致运行流程如下
sequenceDiagram participant client as 客户端 participant server as 服务端 client ->>+ server:用户首次登录 server ->>- client:返回SessionID client ->>+ server:在请求中附带SessionID server ->> server:根据SessionID查询用户信息 server ->>- client:返回用户响应
Token
随着分布式服务端架构的普及,Session 方案逐渐出现了扩展性差、用户信息需要跨实例共享等问题。在微服务与多实例部署的场景下,每个服务都可能运行在不同的物理机或容器中,如果依然依赖服务端保存用户的登录状态,就需要引入复杂的 Session 同步机制,或者依赖集中式的 Session 存储,这不仅增加了系统复杂度,也带来了额外的性能开销和单点故障风险
Token 方案的核心是由客户端来存储用户信息。当用户首次登录网站时,服务端将必要的用户信息和其他信息编码到 token 中(这种性质也被称为自包含),通过 Cookie 返回到客户端中。用户后续访问时,将 token 通过 Cookie 发送到服务端,服务端通过签名机制验证 token 的合法性,同时解码 token,获取其中的用户信息
Token 签名,是指服务端在生成 Token 时,使用一个密钥或密钥对对 Token 的部分或全部内容进行加密计算,生成一段签名(signature),并将该签名附加到 Token 中。
当客户端将 Token 发回给服务端时,服务端可以使用相同的密钥重新计算签名,然后与 Token 中携带的签名进行比对,以验证该 Token 是否被篡改、是否真的由可信的服务端签发。
Token 可以类比作身份证,服务端接收到身份证后,直接可以从中解码出用户信息
大致运行流程如下
sequenceDiagram participant client as 客户端 participant server as 服务端 client ->>+ server:用户首次访问 server ->>- client:返回token client ->>+ server:在请求中附带token server ->> server:服务端从token中解码出用户信息 server ->>- client:返回用户响应
JWT
JWT(Json Web Token)是 Token 方案的一种实现,它基于 JSON 格式
JWT 是由 Header、Payload 和 Signature 组成的 Header.Payload.Signature
格式的字符串
-
Header
描述 JWT 的类型和签名算法,原始数据示例如下
1
2
3
4{
"alg": "HS256",
"typ": "JWT"
}以上内容经过 Base64Url 编码,生成 Header
-
Payload
存储用户信息,通常包含三类声明
- 标准声明:预定义字段,如
iss
(发行者)、exp
(过期时间)、sub
(主题,通常为用户 ID)、iat
(签发时间) - 公共声明:用户自定义字段,如
userId
、username
、role
- 私有声明:特定场景下使用的字段,如
permissions
该部分同样经过 Base64Url 编码,生成 Payload
- 标准声明:预定义字段,如
-
Signature:签名,用于服务端进行合法性验证
该部分由 Header 和 Payload 计算得到,用于服务端验证 JWT 的合法性,计算方法示例如下
1
2encode = Base64UrlEncode(Header) + "." + Base64UrlEncode(Payload)
signature = HMACSHA256(encode, SecretKey)其中,SecretKey 为服务端拥有的加密私钥