面试知识库
极高 进阶

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#

维度SessionJWT
存储服务端(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 可随时删除
plaintext

Spring 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