Java JWT 技术详解与实践指南
1. JWT 基础概念
JWT (JSON Web Token) 是一种开放标准(RFC 7519),用于在各方之间安全传输信息的紧凑且自包含的方式。常用于身份验证和授权场景。
1.1 JWT 结构
JWT 由三部分组成,用 .
分隔:
Header.Payload.Signature
- Header:包含令牌类型和签名算法(如 HS256、RS256)
- Payload:存放有效信息(如用户ID、角色、过期时间)
- Signature:验证令牌完整性和来源的签名
2. Java JWT 实现选型
2.1 常用库对比
库名称 | 特点 | Maven 依赖 |
---|---|---|
JJWT | 简单易用,文档完善 | io.jsonwebtoken:jjwt-api:0.12.3 |
Nimbus JOSE | 功能全面,支持更多JOSE规范 | com.nimbusds:nimbus-jose-jwt:9.37 |
3. 快速入门示例(使用 JJWT)
3.1 添加依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.12.3</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.12.3</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.12.3</version><scope>runtime</scope>
</dependency>
3.2 生成 JWT
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;public String generateToken(String username) {return Jwts.builder().setSubject(username).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时.signWith(SignatureAlgorithm.HS256, "your-256-bit-secret").compact();
}
3.3 解析验证 JWT
public String parseToken(String token) {try {return Jwts.parserBuilder().setSigningKey("your-256-bit-secret").build().parseClaimsJws(token).getBody().getSubject();} catch (Exception e) {throw new RuntimeException("Invalid JWT");}
}
4. 最佳实践
4.1 安全配置
- 密钥管理:使用至少256位的安全密钥
- 过期时间:短期令牌(15-60分钟)结合刷新令牌
- 敏感信息:不要在Payload中存储密码等敏感数据
4.2 与 Spring Security 集成
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/api/auth/**").permitAll().anyRequest().authenticated().and().addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);}
}public class JwtFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {String token = extractToken(request);if (token != null && validateToken(token)) {Authentication auth = getAuthentication(token);SecurityContextHolder.getContext().setAuthentication(auth);}filterChain.doFilter(request, response);}private String extractToken(HttpServletRequest request) {String header = request.getHeader("Authorization");if (header != null && header.startsWith("Bearer ")) {return header.substring(7);}return null;}
}
5. 高级功能
5.1 自定义 Claims
Map<String, Object> claims = new HashMap<>();
claims.put("roles", Arrays.asList("USER", "ADMIN"));Jwts.builder().setClaims(claims)// ...其他配置
5.2 刷新令牌机制
public String refreshToken(String oldToken) {Claims claims = parseClaims(oldToken);if (claims.getExpiration().before(new Date())) {throw new RuntimeException("Token expired");}return generateToken(claims.getSubject());
}
6. 常见问题解决方案
6.1 签名验证失败
- 检查密钥是否一致
- 验证算法是否匹配
- 确认令牌未被篡改
6.2 跨服务验证(RS256 算法)
// 生成密钥对
KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);// 使用私钥签名
Jwts.builder().signWith(keyPair.getPrivate(), RS256)...// 使用公钥验证
Jwts.parserBuilder().setSigningKey(keyPair.getPublic())...
7. 性能优化建议
- 缓存公钥:RS256算法中避免每次请求都读取公钥
- 异步验证:使用CompletableFuture进行并行验证
- 精简Claims:减少Payload数据量
8. 安全注意事项
- 始终使用HTTPS传输JWT
- 防范XSS攻击(避免localStorage存储,推荐HttpOnly Cookie)
- 定期轮换加密密钥
- 实现令牌黑名单机制