极高 进阶
JWT原理与实践#
一句话答案#
JWT 由 Header.Payload.Signature 三部分 Base64 编码拼接而成,服务端用密钥签名验证完整性,无需存储 Session 实现无状态认证;缺点是无法主动失效(需配合 Redis 黑名单)、Token 体积较大。
核心要点
JWT 结构#
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIiwiZXhwIjoxNzE2...}.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header Payload Signature
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "user123", "exp": 1716000000, "roles": ["admin"]}
Signature: HMACSHA256(base64(header) + "." + base64(payload), secret)plaintext认证流程#
1. 用户登录: POST /login {username, password}
2. 服务端验证 → 生成 JWT(含 userId/roles/exp)→ 返回 Token
3. 客户端存储 Token(localStorage / httpOnly Cookie)
4. 后续请求: Authorization: Bearer <token>
5. 服务端: 验签 → 解析 Payload → 获取用户信息 → 鉴权plaintext有状态 Session vs 无状态 JWT#
| 维度 | Session | JWT |
|---|---|---|
| 存储 | 服务端(Redis/内存) | 客户端 |
| 扩展性 | 需要共享 Session(Redis) | 天然支持分布式(无状态) |
| 性能 | 每次请求查 Redis | 本地验签(CPU 计算) |
| 主动失效 | 删除 Session 即可 | 无法主动失效(需黑名单) |
| 安全性 | CSRF 风险 | XSS 风险(存 localStorage) |
| 体积 | SessionId 很小 | Token 较大(几百字节~几KB) |
Token 刷新机制(双 Token)#
Access Token: 有效期短(15min~2h)—— 用于接口鉴权
Refresh Token: 有效期长(7d~30d)—— 用于刷新 Access Token
流程:
1. 登录时签发 accessToken + refreshToken
2. accessToken 过期 → 客户端用 refreshToken 请求 /refresh
3. 服务端验证 refreshToken → 签发新 accessToken
4. refreshToken 过期 → 重新登录
安全措施:
- refreshToken 存 httpOnly Cookie(防 XSS)
- refreshToken 单次使用(用完签发新的)
- refreshToken 可以存 Redis(支持主动失效)plaintext主动失效方案#
问题: JWT 签发后到 exp 之前无法作废(无状态的代价)
方案1: Redis 黑名单
用户登出 → 将 token 或 jti 加入 Redis 黑名单(TTL = 剩余有效期)
每次请求先查黑名单
方案2: Token 版本号
Redis 存 user:{userId}:tokenVersion
JWT payload 含 version 字段
修改密码/登出 → version+1 → 旧 Token 全部失效
方案3: 短有效期 + Refresh Token(推荐)
accessToken 15min 过期,损失窗口小
refreshToken 存 Redis 可随时删除plaintextSpring Boot 集成#
// 生成 Token
String token = Jwts.builder()
.setSubject(user.getId())
.claim("roles", user.getRoles())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
// 验证 Token(Filter 中)
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();java面试回答(2分钟版)
JWT 由 Header、Payload、Signature 三部分 Base64 拼接而成。服务端用 HMAC 或 RSA 对前两部分签名,验证时重新计算签名比对,保证 Token 未被篡改。优势是无状态——服务端不需要存 Session,天然适合分布式架构,任何一台服务器都能验证 Token。主要缺点是无法主动失效:Token 签发后在 exp 之前一直有效,即使用户登出。解决方案是双 Token 机制:短有效期的 accessToken(15分钟)用于鉴权,长有效期的 refreshToken 存 Redis 可随时删除。修改密码或登出时只需删除 refreshToken + 将 accessToken 加黑名单(TTL=剩余有效期)。安全方面:accessToken 放 Authorization Header,refreshToken 放 httpOnly Cookie 防 XSS,加上 HTTPS 防中间人。
追问与易错
追问方向:
- “JWT 怎么主动失效?”→ Redis 黑名单 / Token 版本号 / 短有效期+Refresh Token
- “JWT 和 Session 怎么选?”→ 分布式系统用 JWT(无状态),单体用 Session 也行
- “JWT 被窃取了怎么办?”→ 短有效期减少损失窗口 + HTTPS 防劫持 + httpOnly 防 XSS
- “用 HS256 还是 RS256?”→ 单服务 HS256(对称,快),微服务 RS256(公钥验签,私钥签发)
易错点:
- ❌ “JWT 加密了所以安全”——JWT 只是 Base64 编码+签名,Payload 是明文可解码,不要放敏感数据
- ❌ “JWT 无状态就完全不需要 Redis”——主动失效仍需 Redis 黑名单
- ❌ “Token 放 localStorage 没问题”——XSS 可以偷 localStorage,建议 httpOnly Cookie