package com.goi.erp.token; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import org.springframework.data.domain.AuditorAware; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import jakarta.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; import java.util.Optional; /** * auth-service에서 발급한 JWT 토큰 기반으로 현재 사용자(empId)를 가져오는 AuditorAware 구현체 * * - JPA auditing에서 사용자가 누군지 기록할 때 사용 * - SecurityContextHolder 없이도 동작 가능 * - HttpServletRequest에서 Authorization 헤더를 읽어 토큰 파싱 */ public class ApplicationAuditAware implements AuditorAware { private final String jwtSecret; public ApplicationAuditAware(String jwtSecret) { this.jwtSecret = jwtSecret; } /** * 현재 요청을 수행하는 사용자의 empId 반환 * @return Optional - empId가 없거나 토큰이 유효하지 않으면 Optional.empty() */ @Override public Optional getCurrentAuditor() { HttpServletRequest request = getCurrentHttpRequest(); if (request == null) { return Optional.empty(); } String token = resolveToken(request); if (token == null) { return Optional.empty(); } try { // JWT 파싱 Claims claims = Jwts.parserBuilder() // HMAC SHA 키 객체 생성 (secret 길이와 안전성 체크) .setSigningKey(Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8))) .build() .parseClaimsJws(token) .getBody(); // 토큰에 empId 클레임이 있어야 함 Integer empId = claims.get("empId", Integer.class); return Optional.ofNullable(empId); } catch (Exception e) { // 토큰 파싱/검증 실패 시 Optional.empty() 반환 return Optional.empty(); } } /** * 현재 스레드의 HttpServletRequest 가져오기 * @return HttpServletRequest 또는 null */ private HttpServletRequest getCurrentHttpRequest() { ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attrs == null) return null; return attrs.getRequest(); } /** * HttpServletRequest에서 Authorization 헤더의 Bearer 토큰 추출 * @param request 현재 HttpServletRequest * @return JWT 문자열 또는 null */ private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (bearerToken != null && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } }