在 Web 应用的交互过程中,用户身份认证(Authentication) 是最基础、也是最核心的能力之一。所谓认证,本质上就是回答一个问题:“你是谁?”。
然而,HTTP 协议天生是无状态的——服务器不会主动记住客户端的身份信息。服务器在处理每一次请求时,都无法确认请求是否来自同一个用户。这一特性决定了:认证机制是 Web 应用中必须额外解决的技术问题。
如果每次请求都要求用户重复输入用户名和密码,不仅用户体验极差,也存在严重的安全风险。正是在这样的背景下,Session 认证、Token 认证以及如今主流的 JWT 认证方案逐步演进,并在工程实践中不断融合优化。
一、传统 Session 认证:基于服务器状态的身份绑定
1. Session 的核心思想
Session 是 Web 早期最常用的认证机制,其核心思想是:
| 由服务器保存用户的会话状态,并通过 SessionID 将客户端与服务器状态绑定起来。
Session 本质上是基于 Cookie 实现的身份识别方案。
2. Session 认证流程
完整的 Session 认证流程通常如下:
1. 会话创建: 客户端首次提交用户名、密码等认证信息,服务器验证通过后,为该用户创建一个 Session,用于存储身份信息、权限数据等。
2. SessionID 下发: 服务器将 Session 保存在内存(或数据库、缓存)中,同时生成唯一的 SessionID 返回给客户端。
3. 客户端存储: 客户端收到 SessionID 后,将其存入 Cookie,并与服务器域名绑定。
4. 后续请求认证: 客户端后续请求时,会自动携带 Cookie。服务器提取其中的 SessionID,并查找对应 Session,若存在则认证成功,否则失败。
3. Session 认证的局限性
随着系统规模扩大,Session 机制的缺陷逐渐显现:
- 服务器开销大: Session 多存储在服务器内存中,用户规模增长会导致内存压力迅速增大。
- 扩展性差: 在分布式架构中,Session 默认绑定单台服务器,请求被路由到其他节点时会认证失败,需额外引入 Session 共享方案(如 Redis),增加系统复杂度。
- 安全风险(CSRF): Session 依赖 Cookie 自动携带,容易受到 CSRF(跨站请求伪造)攻击。
二、传统 Token 认证:无状态认证的初步探索
1. Token 认证的设计目标
为解决 Session 的扩展性和安全问题,Token 认证应运而生,其目标是:
| 让服务器不再保存会话状态,实现无状态认证。
2. Token 认证流程
- 客户端提交用户名和密码
- 服务器验证成功后,生成一个 Token 字符串
- 服务器将 Token 存储在数据库或缓存中,并返回给客户端
- 客户端将 Token 保存到本地(如 LocalStorage)
- 客户端每次请求时,在 HTTP Header 中携带 Token
- 服务器从 Header 中取出 Token,通过查询数据库或缓存验证其有效性
3. Token 认证的优缺点
优点:
- 服务器不再保存会话状态,天然支持分布式架构
- Token 通过 Header 传递,避免了 Cookie 带来的 CSRF 风险
缺点:
- 性能损耗: 每次认证都需要查询数据库或缓存
- 退出复杂: 用户退出登录时必须通知服务器删除 Token,否则 Token 在过期前始终有效
传统 Token 虽然是无状态的,但仍然依赖服务器存储 Token,本质上并未彻底摆脱“服务器状态”。
三、JWT 认证:理论上的完全无状态方案
JWT(JSON Web Token)是目前最主流的认证技术,它在传统 Token 的基础上提出了一个关键改进:
| Token 本身携带身份信息,服务器只负责校验,不再存储 Token。
1. JWT 认证流程
- 客户端提交认证信息
- 服务器验证通过后,生成 JWT 并返回给客户端(服务器不保存)
- 客户端将 JWT 保存在本地
- 客户端每次请求时通过 Header 携带 JWT
- 服务器使用密钥解析 JWT:
- 解析成功且未过期 → 认证成功
- 解析失败或过期 → 认证失败
2. JWT 的核心优势
- 无需查库,性能开销低
- 完全无状态,天然适配分布式与微服务架构
- 任意服务器节点都可独立完成认证
四、JWT 的结构组成
JWT 由三部分组成,使用 . 连接:
Header.Payload.Signature
- Header(头部)
- Payload(负载)
- Signature(签名 )
1. Header(头部)
Header 描述 Token 的元信息,包括:
- Token 类型(JWT)
- 签名算法(如 HS256、RS256)
2. Payload(负载)
Payload 用于存储声明(Claims),包括:
- 注册声明:如 exp、iat、iss
- 公共声明:如用户名、角色
- 私有声明:服务端与客户端约定的信息
⚠️ Payload 只是 Base64 编码,并非加密,任何人都可以解码查看,因此不应存放敏感信息。
3. Signature(签名)
Signature 用于保证 Token 不被篡改,由服务器使用密钥对 Header 和 Payload 进行加密生成。服务器通过重新计算签名来验证 JWT 的合法性。
4. JWT编码:
eyJhbGciOiJSUzI1NiIsImtpZCI6IkUyMjJBMTM5ODc2MjI3RUNEREI2NzBGQkY1NTc5QzM2IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2Mjg4MDA2MjgsImV4cCI6MTYyODgwNDIyOCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDoxMDAwMSIsImNsaWVudF9pZCI6IkFjY291bnRfcGFzc3dvcmRfY2xpZW50Iiwic3ViIjoic2EiLCJhdXRoX3RpbWUiOjE2Mjg4MDA2MjcsImlkcCI6ImxvY2FsIiwiVXNlcklkIjoiMSIsIm5hbWUiOiJ3amsiLCJnaXZlbl9uYW1lIjoiamF5Y2V3dSIsImZhbWlseV9uYW1lIjoieXl5IiwiZW1haWwiOiI5Nzc4NjU3NjlAcXEuY29tIiwicm9sZSI6ImFkbWluIiwianRpIjoiREUwNzQ4RDgwQ0NBQzZDNzc1OUM4RTA5QUE2MjNFQjMiLCJpYXQiOjE2Mjg4MDA2MjcsInNjb3BlIjpbIm9wZW5pZCJdLCJhbXIiOlsiY3VzdG9tIl19.zEuO8n_oQ_UuWonV3EQX86G0K-5wSZPPjluaJ0KtDEtXdqftzhTGSzNWgg1-4rCi-2tVFjXuwcoGsWJgtTbfRz4_cuNhorO27g5XNT0toAcbEV5Bhyex4G5nIK_DqDQUqWL-coigAh49m8mEq-lqBuulznITmHcLRqURxD_UjBTcSxItXgMu9_ikCD7IQKYFWu8IsQn4K8FBBbOYdkxAQwPmMb5yMtj_5BM6teFTeGlBOwpR7Ulu498XRSjLumUus4hCBDhdrxCTBI-YKRZEKUiIjtFZbH8xvqKqecmXIJEfldWa1VIAOjWuXPi77PRrNqRV3vgLhj6WBXPSXPjQdQ
地址验证:https://jwt.ms/
eyJhbGciOiJSUzI1NiIsImtpZCI6IkUyMjJBMTM5ODc2MjI3RUNEREI2NzBGQkY1NTc5QzM2IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2Mjg4MDA2MjgsImV4cCI6MTYyODgwNDIyOCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDoxMDAwMSIsImNsaWVudF9pZCI6IkFjY291bnRfcGFzc3dvcmRfY2xpZW50Iiwic3ViIjoic2EiLCJhdXRoX3RpbWUiOjE2Mjg4MDA2MjcsImlkcCI6ImxvY2FsIiwiVXNlcklkIjoiMSIsIm5hbWUiOiJ3amsiLCJnaXZlbl9uYW1lIjoiamF5Y2V3dSIsImZhbWlseV9uYW1lIjoieXl5IiwiZW1haWwiOiI5Nzc4NjU3NjlAcXEuY29tIiwicm9sZSI6ImFkbWluIiwianRpIjoiREUwNzQ4RDgwQ0NBQzZDNzc1OUM4RTA5QUE2MjNFQjMiLCJpYXQiOjE2Mjg4MDA2MjcsInNjb3BlIjpbIm9wZW5pZCJdLCJhbXIiOlsiY3VzdG9tIl19.zEuO8n_oQ_UuWonV3EQX86G0K-5wSZPPjluaJ0KtDEtXdqftzhTGSzNWgg1-4rCi-2tVFjXuwcoGsWJgtTbfRz4_cuNhorO27g5XNT0toAcbEV5Bhyex4G5nIK_DqDQUqWL-coigAh49m8mEq-lqBuulznITmHcLRqURxD_UjBTcSxItXgMu9_ikCD7IQKYFWu8IsQn4K8FBBbOYdkxAQwPmMb5yMtj_5BM6teFTeGlBOwpR7Ulu498XRSjLumUus4hCBDhdrxCTBI-YKRZEKUiIjtFZbH8xvqKqecmXIJEfldWa1VIAOjWuXPi77PRrNqRV3vgLhj6WBXPSXPjQdQ
5.JWT解码:
{
"alg": "RS256", //算法签名
"kid": "E222A139876227ECDDB670FBF5579C36",//令牌id
"typ": "at+jwt"//令牌类型
}.{
"nbf": 1628800628, //生效时间 生效之前无法用
"exp": 1628804228, //过期时间 过期时间后无法用。大于签发时间iat
"iss": "http://localhost:10001",//签发服务地址
"client_id": "Account_password_client",//客户端id
"sub": "sa",
"auth_time": 1628800627,
"idp": "local",
"UserId": "1",
"name": "wjk",
"given_name": "jaycewu",
"family_name": "yyy",
"email": "977865769@qq.com",
"role": "admin",
"jti": "DE0748D80CCAC6C7759C8E09AA623EB3",//一次性操作
"iat": 1628800627,//签发时间
"scope": [
"openid"
],
"amr": [
"custom"
]
}.[Signature]
五、工程实践:JWT + 缓存的混合认证方案
尽管 JWT 在理论上是“完全无状态”的,但在真实工程中,纯 JWT 模式存在明显不足:
- 无法主动失效 Token(登出、封禁无效)
- 权限变更无法即时生效
- Token 泄露后不可控
因此,在实际系统中,JWT 往往会与缓存(如 Redis)结合使用。
当然,这种也可以通过程序去实现(即时通信)
1. JWT + 缓存的核心思路
| 客户端只持有一个随机字符串(Token ID),真正的 JWT 或用户会话信息存储在服务器缓存中。
2. 实际认证流程
- 用户登录成功
- 服务器生成:
- 一个随机 Token(如 UUID)
- 一个 JWT 或用户会话对象
- 将二者映射关系存入缓存:
token_uuid → jwt / userInfo
- 客户端仅保存 token_uuid
- 每次请求时携带该随机 Token
- 服务器通过随机 Token 从缓存中获取 JWT 或用户信息完成认证
- 若缓存中不存在该 Token,则认证失败
3. 这种方案的优势
- 支持主动注销: 删除缓存即可立即失效
- 权限实时生效: 缓存内容可随时更新
- 泄露风险可控: 泄露的只是随机值
- 兼具 Session 的可控性与 Token 的灵活性
六、几种认证方案的对比
| 方案 | 是否存服务器 | 客户端持有 | 是否可主动失效 |
|---|---|---|---|
| Session | 是 | SessionID | ✅ |
| 纯 JWT | 否 | 完整 JWT | ❌ |
| 传统 Token | 是 | Token | ✅ |
| JWT + 缓存 | 是 | 随机 Token | ✅ |
可以理解为:
| JWT + 缓存 = JWT 的解析能力 + Session 的可控性
七、总结:认证机制的真实演进方向
从 Session 到 JWT,认证机制的演进始终围绕三个核心目标展开:
- 降低服务器状态依赖
- 提升系统扩展性
- 增强安全与可控性
JWT 在理论上提供了最优雅的无状态方案,而在工程实践中,JWT + 缓存 则成为安全性、性能与可维护性之间的最佳平衡方案。这也是为什么在真实生产系统中,“纯 JWT”并不常见,而“JWT 登录”往往是一个混合实现。
在使用 JWT 时,应特别注意:
- 不在 Payload 中存储敏感信息
- 严格保护服务器私钥
- 合理设置 Token 过期时间
- 结合刷新 Token 或缓存控制机制
至此,JWT 已不仅是一种规范,更是一套成熟的工程实践体系。
895

被折叠的 条评论
为什么被折叠?



