JWT令牌机制完全指南
JWT令牌机制完全指南
前言
JWT(JSON Web Token)是现代应用中最常用的令牌格式,具有无状态、可验证的特点。本文将详细介绍JWT的实现和使用。
一、JWT结构
1.1 JWT组成
┌─────────────────────────────────────────────────────┐ │ JWT Structure │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Header │ │ Payload │ │ Signature │ │ │ │ eyJhbGci...│ │ eyJzdWIiL...│ │ QjJhNmRp... │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ Base64 Base64 Base64 │ └─────────────────────────────────────────────────────┘二、JWT实现
2.1 JWT工具类
@Service @RequiredArgsConstructor public class JwtTokenProvider { private final AppProperties appProperties; public String generateToken(Authentication authentication) { UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); Date now = new Date(); Date expiryDate = new Date(now.getTime() + appProperties.getJwt().getExpirationMs()); return Jwts.builder() .setSubject(userPrincipal.getId().toString()) .claim("username", userPrincipal.getUsername()) .claim("email", userPrincipal.getEmail()) .claim("roles", userPrincipal.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList())) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, appProperties.getJwt().getSecret()) .compact(); } public String generateTokenFromUserId(Long userId, String username) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + appProperties.getJwt().getExpirationMs()); return Jwts.builder() .setSubject(userId.toString()) .claim("username", username) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, appProperties.getJwt().getSecret()) .compact(); } public Long getUserIdFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey(appProperties.getJwt().getSecret()) .parseClaimsJws(token) .getBody(); return Long.parseLong(claims.getSubject()); } public String getUsernameFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey(appProperties.getJwt().getSecret()) .parseClaimsJws(token) .getBody(); return claims.get("username", String.class); } public List<String> getRolesFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey(appProperties.getJwt().getSecret()) .parseClaimsJws(token) .getBody(); return claims.get("roles", List.class); } public boolean validateToken(String authToken) { try { Jwts.parser() .setSigningKey(appProperties.getJwt().getSecret()) .parseClaimsJws(authToken); return true; } catch (SecurityException ex) { logger.error("Invalid JWT signature"); } catch (MalformedJwtException ex) { logger.error("Invalid JWT token"); } catch (ExpiredJwtException ex) { logger.error("Expired JWT token"); } catch (UnsupportedJwtException ex) { logger.error("Unsupported JWT token"); } catch (IllegalArgumentException ex) { logger.error("JWT claims string is empty"); } return false; } }2.2 Token刷新
@Service @RequiredArgsConstructor public class TokenRefreshService { private final JwtTokenProvider tokenProvider; private final RedisTemplate<String, String> redisTemplate; public String refreshToken(String refreshToken) { if (!tokenProvider.validateToken(refreshToken)) { throw new TokenException("Invalid refresh token"); } // 检查refresh token是否在黑名单 if (isTokenBlacklisted(refreshToken)) { throw new TokenException("Refresh token has been revoked"); } Long userId = tokenProvider.getUserIdFromToken(refreshToken); String username = tokenProvider.getUsernameFromToken(refreshToken); // 生成新的access token return tokenProvider.generateTokenFromUserId(userId, username); } public void revokeRefreshToken(String refreshToken) { // 将refresh token加入黑名单 String key = "refresh_token:blacklist:" + refreshToken; long expiration = tokenProvider.getExpiration(refreshToken); redisTemplate.opsForValue().set(key, "revoked", Duration.ofMillis(expiration)); } private boolean isTokenBlacklisted(String token) { String key = "refresh_token:blacklist:" + token; return Boolean.TRUE.equals(redisTemplate.hasKey(key)); } }三、总结
JWT是实现无状态认证的核心技术,通过合理的生成、验证和刷新机制,可以构建安全可靠的身份认证系统。
