共计 2359 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点
在用户行为记录(ActivityRecord)系统中,Token 管理是一个容易被忽视但极其关键的环节。很多开发团队在初期往往会遇到以下典型问题:

- 明文传输导致的安全风险 :直接使用用户 ID 或简单编码的 Token,容易被中间人攻击窃取
- 缺乏时效性引发的重放攻击 :没有有效期的 Token 一旦泄露,攻击者可以无限期重复使用
- 高并发下的性能瓶颈 :每次请求都查询数据库验证 Token,导致系统负载飙升
技术方案对比
JWT vs Opaque Token
- JWT(JSON Web Token)
- 优点:自包含(包含签名和有效期),无需后端存储
-
缺点:Payload 体积较大,无法主动失效
-
Opaque Token(不透明令牌)
- 优点:服务端完全控制,可以即时撤销
- 缺点:需要每次验证都查询存储系统
为什么选择 HMAC+SHA256
HMAC(Hash-based Message Authentication Code)结合 SHA256 提供了:
- 计算效率高,适合高频验证
- 密钥可控,便于轮换
- 抗碰撞性强,安全性有保障
核心实现(Spring Boot 示例)
Token 生成设计
public String generateToken(User user) {Map<String, Object> claims = new HashMap<>();
claims.put("userId", user.getId());
claims.put("scope", "activity:read activity:write");
claims.put("iat", System.currentTimeMillis());
return Jwts.builder()
.setClaims(claims)
.setExpiration(new Date(System.currentTimeMillis() + 3600_000))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();}
关键要素:
- 包含用户 ID 和权限范围(scope)
- 记录签发时间(iat)
- 设置 1 小时有效期
签名验证实现
public boolean validateToken(String token) {
try {Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
return !isTokenBlacklisted(token); // 检查黑名单
} catch (Exception e) {log.warn("Invalid token: {}", e.getMessage());
return false;
}
}
双 Token 刷新方案
- Access Token:短有效期(1 小时),用于业务请求
- Refresh Token:长有效期(7 天),存储在 HttpOnly Cookie 中
刷新流程:
@PostMapping("/refresh")
public ResponseEntity<?> refreshToken(@CookieValue String refreshToken) {if (!refreshTokenService.validate(refreshToken)) {return ResponseEntity.status(401).build();}
String newAccessToken = tokenService.generateToken(refreshTokenService.getUser(refreshToken)
);
return ResponseEntity.ok()
.header(HttpHeaders.AUTHORIZATION, newAccessToken)
.build();}
生产级考量
Redis 黑名单实现
public void invalidateToken(String token) {
// Token 剩余有效期内加入黑名单
long ttl = getTokenRemainingTime(token);
redisTemplate.opsForValue().set("token:blacklist:" + token, "1", ttl, TimeUnit.SECONDS);
}
安全配置
# application.yml
server:
ssl:
enabled: true
servlet:
session:
cookie:
secure: true
same-site: strict
Prometheus 监控
@Bean
public MeterBinder tokenMetrics(TokenService tokenService) {return registry -> Gauge.builder("app.tokens.active")
.description("Active tokens count")
.register(registry);
}
避坑指南
- 敏感数据 :绝对不要在 Token 中存储密码、银行卡号等敏感信息
- HTTPS 强制 :Spring Security 配置中启用 requireSecure()
- 时钟同步 :分布式系统使用 NTP 服务保证各节点时间一致
互动与进阶
思考题
如何在不使用黑名单的情况下实现 Token 的主动失效?
提示:可以考虑以下方案:
– 密钥轮换(所有旧 Token 立即失效)
– 用户级版本号(每次失效递增版本)
性能测试建议
使用 JMeter 对比测试:
1. HS256 vs RS256 签名算法
2. 不同 Token 长度对 QPS 的影响
3. 开启 / 关闭黑名单检查的吞吐量差异
总结
通过合理的 Token 设计,我们可以在保证安全性的同时兼顾系统性能。建议在实际项目中:
- 根据业务场景选择 Token 策略
- 实施完善的监控告警
- 定期进行安全审计
希望本文能帮助你避开 ActivityRecord Token 管理的那些坑!
正文完
发表至: 技术分享
近一天内
