package com.goi.erp.token; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.goi.erp.common.permission.PermissionParser; import com.goi.erp.common.permission.PermissionSet; import java.security.Key; import java.util.List; import java.util.function.Function; /** * - DB 접근 없음 * - JWT에 포함된 empUuid, 이름, roles, permissions 추출 * - 토큰 유효기간 체크 가능 */ @Service public class JwtService { @Value("${application.security.jwt.secret-key}") private String secretKey; @Value("${application.security.jwt.expiration}") private long jwtExpiration; /** * empUuid(sub) 추출 */ public String extractEmpUuid(String token) { return extractClaim(token, Claims::getSubject); } /** * loginId 추출 */ public String extractLoginId(String token) { return extractClaim(token, claims -> claims.get("loginId", String.class)); } /** * firstName 추출 */ public String extractFirstName(String token) { return extractClaim(token, claims -> claims.get("firstName", String.class)); } /** * lastName 추출 */ public String extractLastName(String token) { return extractClaim(token, claims -> claims.get("lastName", String.class)); } /** * roles 리스트 추출 */ @SuppressWarnings("unchecked") public List extractRoles(String token) { return extractClaim(token, claims -> (List) claims.get("roles")); } /** * permissions 리스트 추출 */ @SuppressWarnings("unchecked") public List extractPermissions(String token) { return extractClaim(token, claims -> (List) claims.get("permissions")); } /** * 토큰 만료 여부 확인 */ public boolean isTokenExpired(String token) { return extractClaim(token, Claims::getExpiration).before(new java.util.Date()); } /** * 토큰 유효성 검사 (만료 체크) */ public boolean isTokenValid(String token) { return !isTokenExpired(token); } /** * JWT에서 Claims 추출 */ public T extractClaim(String token, Function claimsResolver) { final Claims claims = extractAllClaims(token); return claimsResolver.apply(claims); } /** * JWT 전체 Claims 추출 */ private Claims extractAllClaims(String token) { return Jwts.parserBuilder() .setSigningKey(getSignInKey()) .build() .parseClaimsJws(token) .getBody(); } /** * Permission Set 변환 */ @SuppressWarnings("unchecked") public PermissionSet getPermissions(String token) { Claims claims = extractAllClaims(token); List permissions = claims.get("permissions", List.class); return PermissionParser.parse(permissions); } private Key getSignInKey() { byte[] keyBytes = Decoders.BASE64.decode(secretKey); // auth-service와 동일한 Base64 secret return Keys.hmacShaKeyFor(keyBytes); } public static void main(String[] args) { JwtService jwtService = new JwtService(); jwtService.secretKey = "D0HaHnTPKLkUO9ULL1Ulm6XDZjhzuFtvTCcxTxSoCS8="; String token = "eyJhbGciOiJIUzI1NiJ9.eyJmaXJzdE5hbWUiOiJNSVMiLCJsYXN0TmFtZSI6IkNTIiwibG9naW5JZCI6ImNzX21pcyIsInBlcm1pc3Npb25zIjpbIkg6UjpTIiwiQzpDOkEiLCJDOlI6QSIsIkM6VTpBIiwiQzpEOkEiXSwicm9sZXMiOlsiQ1MgU3RhZmYiXSwic3ViIjoiMWU3NTU4YzYtOTFhZC00ZDcxLTg3ZTUtZGJjZmZiYjk5Zjg1IiwiaWF0IjoxNzY0MzQ3Nzg1LCJleHAiOjIwNzk3MDc3ODV9.lL-ZHEpiribxIrNmeYp6LAeU11z-KuRbgELkWjHCCSc"; // user 정보 Claims claims = jwtService.extractAllClaims(token); System.out.println("Subject (emp_uuid): " + claims.getSubject()); System.out.println("Roles: " + claims.get("roles")); System.out.println("Roles: " + claims.get("permissions")); System.out.println("IssuedAt: " + claims.getIssuedAt()); System.out.println("Expiration: " + claims.getExpiration()); System.out.println("FirstName: " + claims.get("firstName", String.class)); System.out.println("LastName: " + claims.get("lastName", String.class)); // 모든 Claims 확인 // Claims claims = Jwts.parserBuilder() // .setSigningKey(Keys.hmacShaKeyFor("".getBytes())) // .build() // .parseClaimsJws(token) // .getBody(); System.out.println("Claims: " + claims); } }