共计 1735 个字符,预计需要花费 5 分钟才能阅读完成。
概念辨析:协议层的本质差异
根据 RFC 7235 和 RFC 6750 的定义:

-
Authorization 头 是 HTTP 协议标准头部,格式为
Authorization: <type> <credentials>。例如 Bearer Token 模式:GET /resource HTTP/1.1 Authorization: Bearer mF_9.B5f-4.1JqM -
Token则是具体的凭证实现,常见类型包括:
- 不透明令牌(Opaque Token):如随机字符串,需后端校验
- 自包含令牌(如 JWT):包含签名和声明的结构化数据
关键区别在于:Authorization 是传输载体,Token 是凭证实体。就像信封(Header)和信件内容(Token)的关系。
典型混用导致的漏洞
-
CSRF 攻击:错误地将 Token 存在 Cookie 中而非 Authorization 头,导致浏览器自动携带引发跨站请求伪造
-
权限提升 :客户端修改 JWT 的
roles声明但服务端未验证签名(如 alg=none 攻击) -
Token 泄漏:Authorization 头未使用 HTTPS 传输,导致中间人窃取凭证
技术方案选型对比
| 方案 | 适用场景 | Spring Security 配置要点 |
|---|---|---|
| Cookie/Session | 需要服务端状态的 Web 应用 | .sessionManagement().sessionCreationPolicy(STATELESS)禁用 |
| JWT | 无状态分布式系统 | .oauth2ResourceServer().jwt() |
| Opaque Token | 需要即时吊销的场景 | .introspectionClientCredentials() |
OAuth2.0 代码实战
JWT 生成示例(HS256)
public String generateToken(UserDetails user) {return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(user.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(Keys.hmacShaKeyFor(secret.getBytes()), SignatureAlgorithm.HS256)
.compact();}
Redis 存储 Refresh Token
@Repository
public class RedisTokenRepository {
private final RedisTemplate<String, String> template;
public void storeRefreshToken(String username, String token) {template.opsForValue().set(
"refresh:" + username,
token,
Duration.ofDays(30)
);
}
}
生产环境考量
- Token 过期策略:
- Access Token 建议设置较短有效期(如 15 分钟)
-
Refresh Token 建议设置较长有效期(如 7 天)并绑定设备指纹
-
公钥分发:
- 使用 JWKS 端点动态提供公钥(
/.well-known/jwks.json) - 定期轮换密钥(建议每月)但保留旧密钥用于过渡
避坑指南
- JWT Payload 安全:
- 不要存储用户敏感信息(如密码、支付信息)
-
声明字段尽量使用缩写(如
sub而非username) -
签名验证:
@Bean JwtDecoder jwtDecoder() {return NimbusJwtDecoder.withPublicKey(publicKey).build();} -
防重放攻击:
- 在 JWT 中加入
jti唯一标识 - 服务端维护短期 Token 使用记录(如 5 秒窗口期)
延伸阅读
在实际项目中,建议结合具体业务场景选择认证方案。对于内部管理系统,Session 可能更简单;而对微服务架构,JWT+OAuth2.0 的组合更有优势。安全无小事,每次实现身份验证时都应当问自己:这个设计能否通过 OWASP Top 10 的检验?
正文完
