前言
HTTP 协议本身是无状态的,这意味着服务器无法自动识别两次请求是否来自同一个用户。为了实现“登录状态保持”,前端开发中主要有两种主流方案:传统的 Cookie + Session 模式和现代的 Token (主要是 JWT) 模式。本文将带你深入剖析两者的原理、区别及应用场景。
一、 传统方案:Cookie + Session
这是最经典的解决方案,核心在于“服务端存储”。
1. 实现原理
- 登录:用户发送账号密码,服务器验证通过。
- 创建 Session:服务器在内存(或 Redis)中创建一个 Session 对象,存储用户信息,并生成一个唯一的
SessionID。 - 返回 Cookie:服务器将
SessionID写入 HTTP 响应头的Set-Cookie字段中。 - 保持状态:浏览器收到响应后自动将 Cookie 存入本地。下次请求时,浏览器会自动携带包含
SessionID的 Cookie。 - 校验:服务器解析 Cookie 中的
SessionID,去内存中查找对应的 Session 对象,从而确定用户身份。
2. 优缺点分析
-
优点:
- 技术成熟,框架支持度高(如 Java 的 JSESSIONID)。
- 控制力强(服务器可以随时废弃某个 SessionID 实现强制下线)。
-
缺点:
- 服务器压力大:每个在线用户都需要占用服务器内存,用户量大时开销巨大。
- 扩展性差(集群问题) :在多台服务器集群下,需要解决“Session 共享”问题(通常需引入 Redis),否则用户在这个服务器登录,下一次请求到了另一台服务器就失效了。
- 移动端限制:原生 APP(Android/iOS)对 Cookie 的支持不如浏览器友好,处理起来较麻烦。
- CSRF 风险:基于 Cookie 的自动发送机制,容易遭受跨站请求伪造攻击。
二、 现代方案:Token (以 JWT 为主)
随着前后端分离和移动互联的发展,Token(令牌)技术逐渐成为主流,尤其是 JWT (JSON Web Token) 。它的核心在于“时间换空间”,服务器不再存储登录状态。
1. 实现原理
- 登录:用户发送账号密码,服务器验证通过。
- 生成 Token:服务器使用一套加密算法(如 HMACSHA256)和密钥,将用户信息(如 UserID、权限)签名生成一个字符串(Token)。注意:服务器不存储这个 Token。
- 返回 Token:服务器将 Token 返回给客户端。
- 存储与携带:客户端(浏览器/APP)将 Token 存储在
localStorage、sessionStorage或Cookie中。下次请求时,通常将 Token 放入 HTTP 请求头的Authorization字段中(格式:Bearer <token>)。 - 校验:服务器收到请求后,用相同的密钥和算法解密/校验签名。如果签名匹配且未过期,即认为合法。
2. 核心优势
- 无状态 (Stateless) :服务器不需要存储 Session,极大降低了服务器内存压力。
- 支持集群:只要所有服务器使用相同的密钥(Secret),无论请求打到哪台服务器都能通过校验,天生支持分布式架构。
- 跨平台/跨域:非常适合移动端 APP、小程序以及前后端分离的跨域场景。
- 性能高:解析 Token 的计算时间通常远小于查询数据库或 Redis 的时间。
三、 Token 的结构解密
一个标准的 Token(如 JWT)通常由三部分组成,中间用 . 分隔:
Header.Payload.Signature
1. 关键字段说明
-
Header (头部) :声明类型(JWT)和加密算法(如 HS256)。
-
Payload (负载) :存放有效信息(注意:这里的信息虽然经过 Base64 编码但未加密,任何人都能解码看到,所以不要放密码等敏感信息)。
- 用户标识 (sub/uid) :User ID,用户的唯一标识。
- 权限/角色 (scope/role) :标识该用户是管理员还是普通用户。
- 过期时间 (exp) :Expiration Time,Token 何时失效。
- 签发时间 (iat) :Issued At,Token 是什么时候生成的。
-
Signature (签名) :这是最关键的部分。服务器用密钥对 Header 和 Payload 进行签名。如果攻击者修改了 Payload 里的权限,签名校验就会失败。
四、 总结:如何选择?
| 维度 | Cookie + Session | Token (JWT) |
|---|---|---|
| 状态存储 | 服务端(内存/数据库) | 客户端(自身携带信息) |
| 服务器压力 | 高(占内存) | 低(仅需 CPU 计算) |
| 分布式支持 | 需配合 Redis 做 Session 共享 | 天生支持 |
| 客户端支持 | 浏览器友好,APP 较差 | 全平台通用 |
| 安全性 | 防 CSRF 需额外处理 | 需防 XSS(若存 localStorage) |
| 注销机制 | 容易(服务端删除 Session) | 较难(需配合黑名单机制) |
面试建议:
如果面试官问“Token 安全吗?”,一定要回答:Token (JWT) 的 Payload 部分默认只是 Base64 编码,不是加密,所以不能存敏感数据。它的安全性在于签名,保证数据不被篡改。