共计 2393 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
最近在排查线上问题时,发现 Nginx 日志中频繁出现 401 状态码。通过 Wireshark 抓包分析,发现这些请求都携带了过期的 JWT token。这种场景下,客户端仍然在尝试使用已失效的 token 访问受保护资源,导致服务端持续返回 401 Unauthorized 响应。

- 典型场景:用户登录后长时间未操作,token 过期但仍发起请求
- 日志特征:
[error] 401#0: *123456 client sent invalid token - 根本原因:客户端未及时刷新或更新认证凭证
技术对比
JWT 无状态方案
- 优点:服务端无需存储会话状态,适合分布式系统
- 缺点:令牌过期后无法主动撤销,存在安全时间窗口
Session 有状态方案
- 优点:服务端可主动终止会话
- 缺点:需要集中式会话存储,增加系统复杂度
关键差异点:
- JWT 的 expire 时间一旦设置无法中途修改
- Session 可通过服务端存储立即失效
- JWT 在过期时间窗口内仍可被恶意使用
解决方案
Spring Boot 拦截器实现
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenRefreshInterceptor implements HandlerInterceptor {
private final RedisTemplate<String, String> redisTemplate;
private final JwtTokenProvider tokenProvider;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = resolveToken(request);
if (token == null) return true;
if (tokenProvider.isTokenExpired(token) && !isInBlacklist(token)) {String newToken = tokenProvider.refreshToken(token);
redisTemplate.opsForValue().set(token, "revoked",
Duration.ofMillis(tokenProvider.getRemainingTime(token)));
response.setHeader("X-New-Token", newToken);
}
return true;
}
private boolean isInBlacklist(String token) {return Boolean.TRUE.equals(redisTemplate.hasKey(token));
}
}
Postman 测试流程
-
获取初始 token
curl -X POST 'https://api.example.com/auth/login' \ -H 'Content-Type: application/json' \ -d '{"username":"test","password":"123456"}' -
使用过期 token 访问
curl -X GET 'https://api.example.com/protected' \ -H 'Authorization: Bearer expired.token.xxx' -
检查响应头中的 X -New-Token
生产实践
分布式锁处理并发刷新
RLock lock = redissonClient.getLock("token_refresh:" + userId);
try {if (lock.tryLock(1, 5, TimeUnit.SECONDS)) {// 执行 token 刷新逻辑}
} finally {lock.unlock();
}
监控指标配置
# Prometheus 配置示例
- name: http_requests
rules:
- alert: High401ErrorRate
expr: rate(http_requests_total{status="401"}[5m]) > 0.1
for: 10m
labels:
severity: critical
避坑指南
- 前端处理 401 响应时应该立即清除本地存储的 token
- 刷新 token 时必须验证 refresh_token 是否具有正确的 scope
- 在 JWT 验证逻辑中显式禁用 none 算法:
Jwts.parserBuilder() .require("alg", "RS256") .build();
延伸思考
零信任架构设计
- 采用超短期令牌(如 5 分钟有效期)
- 每次请求都进行设备指纹验证
- 实现持续性的认证流程
mTLS 特殊处理
当 CA 证书失效时:
1. 客户端应保留旧证书用于 401 重试
2. 服务端提供证书更新端点
3. 设计双向证书轮换机制
sequenceDiagram
participant Client
participant Server
participant AuthService
Client->>Server: 请求携带过期 token
Server->>AuthService: 验证 token(已过期)
AuthService-->>Server: 401 响应
Server->>Client: 返回 401+ 刷新地址
Client->>AuthService: 使用 refresh_token 请求新 token
AuthService-->>Client: 返回新 access_token
Client->>Server: 使用新 token 重试请求
Server-->>Client: 返回 200 正常响应
总结下来,处理 401 无效 token 需要系统化的解决方案。从协议层理解其本质,在实现时考虑分布式环境下的并发问题,并通过完善的监控及时发现问题。最重要的是建立标准的令牌更新流程,避免因认证失败导致用户体验下降或系统稳定性问题。
正文完
发表至: 未分类
近一天内
