Session 与 JWT 认证如何选型?无状态认证方案如何设计?
结论先行:Session 认证把状态存在服务端(内存/Redis),客户端只持会话 ID,优点是可随时失效、可控性强;JWT 把用户信息与签名放进客户端令牌,服务端无状态、天然适合水平扩展,代价是签发后难立即撤销、载荷越长体积越大。微服务/前后端分离常用短时 JWT + refresh token 组合,纯内网/强管控场景仍可回归 Session。
一、两种方案对比
| 维度 | Session | JWT |
|---|---|---|
| 状态存放 | 服务端(内存/Redis) | 客户端(无状态) |
| 扩展性 | 需共享存储/粘性会话 | 任意节点可验签 |
| 失效控制 | 删 Session 即失效 | 难撤销,等过期/黑名单 |
| 安全注意 | CSRF(Cookie 自动携带) | XSS(localStorage 存储)、密钥泄露 |
| 适合场景 | 单体、内网、强管控 | 微服务、跨域、开放 API |
二、JWT 结构
header.payload.signature
// header: {"alg":"HS256","typ":"JWT"}
// payload: {"sub":"1001","exp":1700000000,"scope":"read"}
// signature: HMACSHA256(base64(header)+"."+base64(payload), secret)
- 三部分:头部(算法)、载荷(声明)、签名(防篡改);
- 典型做法:登录校验通过后用密钥签发 access token(15
30 分钟),另发 refresh token(数小时数天); - 验签在网关或资源服务完成:本地解析 + 验签即可,不查库,这是“无状态”的核心。
三、无状态认证设计要点
- 令牌携带方式:
Authorization: Bearer <token>,不放 URL; - 客户端存储:优先 httpOnly + Secure Cookie(防 XSS 读取),避免 localStorage;
- 刷新与续期:access 过期用 refresh token 换新,refresh 需可吊销(存 Redis 白/黑名单);
- 服务端解析:自定义 OncePerRequestFilter → 解析验签 → 把 Authentication 写入 SecurityContext;
- 主动失效手段:维护 jti 黑名单、缩短过期时间、改密钥强制全员失效;
- 敏感操作二次校验:JWT 只能证明“曾登录”,高危接口仍建议验密码/验证码。
常见追问 / 记忆点
- 追问:JWT 为什么难实现“踢人下线”?答:令牌由客户端自持,服务端无状态即无撤销点,需黑名单或缩短有效期补偿。
- 追问:Session 一定比 JWT 慢吗?答:单体上差距很小;瓶颈在分布式共享存储与序列化,JWT 免查询但多付带宽与验签成本。
- 记忆点:Session 强在可控、JWT 强在无状态;生产多用“短 JWT + refresh + 必要黑名单”的折中。