← 返回首页
🔒

JWT架构:Token结构与刷新安全

📂 architecture ⏱ 2 min 337 words

JWT架构:Token结构与刷新安全

JWT令牌结构

JWT由Header、Payload和Signature三部分组成,每部分使用Base64URL编码。

// JWT令牌构建
@Component
public class JWTTokenBuilder {
    
    private final RSAPrivateKey privateKey;
    private final JWTConfig config;
    
    public String createAccessToken(User user, List<String> scopes) {
        Instant now = Instant.now();
        
        String token = Jwts.builder()
            .setSubject(user.getId())
            .setIssuer(config.getIssuer())
            .setAudience(config.getAudience())
            .setIssuedAt(Date.from(now))
            .setExpiration(Date.from(now.plus(config.getAccessTokenLifetime())))
            .claim("email", user.getEmail())
            .claim("roles", user.getRoles())
            .claim("scope", String.join(" ", scopes))
            .signWith(privateKey, SignatureAlgorithm.RS256)
            .compact();
        
        return token;
    }
    
    public RefreshToken createRefreshToken(User user) {
        Instant now = Instant.now();
        String tokenId = UUID.randomUUID().toString();
        
        String token = Jwts.builder()
            .setId(tokenId)
            .setSubject(user.getId())
            .setIssuer(config.getIssuer())
            .setIssuedAt(Date.from(now))
            .setExpiration(Date.from(now.plus(config.getRefreshTokenLifetime())))
            .claim("token_type", "refresh")
            .signWith(privateKey, SignatureAlgorithm.RS256)
            .compact();
        
        return RefreshToken.builder()
            .token(token)
            .tokenId(tokenId)
            .userId(user.getId())
            .expiresAt(now.plus(config.getRefreshTokenLifetime()))
            .build();
    }
}

令牌验证与解析

// JWT验证服务
@Service
public class JWTValidator {
    
    private final RSAPublicKey publicKey;
    private final JWTConfig config;
    private final TokenBlacklistService blacklistService;
    
    public Claims validateToken(String token) {
        try {
            // 解析并验证签名
            Claims claims = Jwts.parserBuilder()
                .setSigningKey(publicKey)
                .requireIssuer(config.getIssuer())
                .requireAudience(config.getAudience())
                .build()
                .parseClaimsJws(token)
                .getBody();
            
            // 检查黑名单
            if (blacklistService.isBlacklisted(claims.getId())) {
                throw new JWTException("令牌已被撤销");
            }
            
            // 验证过期时间
            if (claims.getExpiration().before(new Date())) {
                throw new JWTException("令牌已过期");
            }
            
            return claims;
            
        } catch (ExpiredJwtException e) {
            throw new JWTException("令牌已过期", e);
        } catch (UnsupportedJwtException e) {
            throw new JWTException("不支持的令牌类型", e);
        } catch (MalformedJwtException e) {
            throw new JWTException("令牌格式错误", e);
        } catch (SignatureException e) {
            throw new JWTException("签名验证失败", e);
        }
    }
}

令牌刷新机制

// 令牌刷新服务
@Service
public class TokenRefreshService {
    
    private final JWTTokenBuilder tokenBuilder;
    private final RefreshTokenStore refreshTokenStore;
    private final JWTValidator validator;
    
    public TokenPair refreshTokens(String refreshToken) {
        // 验证刷新令牌
        Claims claims = validator.validateToken(refreshToken);
        
        // 检查是否为刷新令牌
        if (!"refresh".equals(claims.get("token_type"))) {
            throw new SecurityException("无效的刷新令牌");
        }
        
        String tokenId = claims.getId();
        String userId = claims.getSubject();
        
        // 验证刷新令牌是否存在且未使用
        RefreshToken storedToken = refreshTokenStore.get(tokenId);
        if (storedToken == null || storedToken.isUsed()) {
            // 可能存在令牌盗用,撤销所有相关令牌
            revokeAllUserTokens(userId);
            throw new SecurityException("刷新令牌已被使用,可能存在安全风险");
        }
        
        // 标记当前刷新令牌为已使用
        refreshTokenStore.markAsUsed(tokenId);
        
        // 生成新的令牌对
        User user = userService.findById(userId);
        String newAccessToken = tokenBuilder.createAccessToken(user, 
            Arrays.asList(claims.get("scope").toString().split(" ")));
        RefreshToken newRefreshToken = tokenBuilder.createRefreshToken(user);
        
        // 存储新的刷新令牌
        refreshTokenStore.save(newRefreshToken);
        
        return TokenPair.builder()
            .accessToken(newAccessToken)
            .refreshToken(newRefreshToken.getToken())
            .expiresIn(3600)
            .build();
    }
    
    private void revokeAllUserTokens(String userId) {
        refreshTokenStore.revokeAllForUser(userId);
        blacklistService.blacklistAllForUser(userId);
    }
}

安全最佳实践

# JWT安全配置
jwt:
  security:
    # 密钥管理
    key_rotation:
      enabled: true
      interval: 90d
      algorithm: RS256
    
    # 令牌配置
    access_token:
      lifetime: 15m
      header: Authorization
      prefix: "Bearer "
    
    refresh_token:
      lifetime: 7d
      rotation: true
      absolute_lifetime: 30d
      reuse_detection: true
    
    # 安全选项
    options:
      prevent_replay: true
      require_https: true
      validate_claims: true
      check_blacklist: true

JWT架构通过合理的令牌结构设计、安全的刷新机制和完善的防护措施,确保身份验证系统的可靠性和安全性。