인증/권한 업무 규칙과 전환 불변식 추출 (codex-bais-final3-20260713-192718-BAIS-SPRING-ANA-AUTH-001)

This commit is contained in:
forge-bot 2026-07-13 10:30:33 +00:00
parent 01f2a87199
commit a3d57302e7

View file

@ -0,0 +1,101 @@
package com.example.auth.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
/**
* JWT Token Provider - preserves AUTH-010, AUTH-011, AUTH-003 invariants.
* JWT structure: {sub, roles[], exp, iat}
* Access token TTL: 30 minutes (AUTH-003)
* Refresh token: 7 days, one-time use (AUTH-011)
*/
@Component
public class JwtTokenProvider {
private static final long ACCESS_TOKEN_TTL_MS = 30 * 60 * 1000;
private static final long REFRESH_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
private final SecretKey secretKey;
private final TokenBlacklistService blacklistService;
public JwtTokenProvider(TokenBlacklistService blacklistService) {
this.secretKey = Keys.hmacShaKeyFor(
System.getenv("JWT_SECRET").getBytes(StandardCharsets.UTF_8));
this.blacklistService = blacklistService;
}
public String generateAccessToken(String username, List<String> roles) {
Date now = new Date();
Date expiry = new Date(now.getTime() + ACCESS_TOKEN_TTL_MS);
return Jwts.builder()
.subject(username)
.claim("roles", roles)
.issuedAt(now)
.expiration(expiry)
.signWith(secretKey)
.compact();
}
public String generateRefreshToken(String username) {
Date now = new Date();
Date expiry = new Date(now.getTime() + REFRESH_TOKEN_TTL_MS);
return Jwts.builder()
.subject(username)
.claim("type", "refresh")
.issuedAt(now)
.expiration(expiry)
.signWith(secretKey)
.compact();
}
public JwtClaims getClaims(String token) {
Claims claims = Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(token)
.getPayload();
@SuppressWarnings("unchecked")
List<String> roles = claims.get("roles", List.class);
return new JwtClaims(
claims.getSubject(),
roles != null ? roles : List.of(),
claims.getIssuedAt(),
claims.getExpiration()
);
}
public boolean validateToken(String token) {
try {
if (blacklistService.isBlacklisted(token)) {
return false; // AUTH-012: revoked tokens invalid
}
Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
public record JwtClaims(
String subject,
List<String> roles,
Date issuedAt,
Date expiration
) {}
}