101 lines
3.2 KiB
Java
101 lines
3.2 KiB
Java
package com.zioinfo.mall.auth;
|
|
|
|
import io.jsonwebtoken.*;
|
|
import io.jsonwebtoken.security.Keys;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
import javax.crypto.SecretKey;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Date;
|
|
|
|
@Slf4j
|
|
@Component
|
|
public class JwtUtil {
|
|
|
|
@Value("${guardia.jwt.secret:guardia-mall-jwt-secret-2026-minimum-256bit-key-zioinfo}")
|
|
private String secret;
|
|
|
|
@Value("${guardia.jwt.expiration:86400000}")
|
|
private long expirationMs;
|
|
|
|
private SecretKey key() {
|
|
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
|
|
public String generate(String username, String role) {
|
|
return Jwts.builder()
|
|
.subject(username)
|
|
.claim("role", role)
|
|
.issuedAt(new Date())
|
|
.expiration(new Date(System.currentTimeMillis() + expirationMs))
|
|
.signWith(key())
|
|
.compact();
|
|
}
|
|
|
|
/**
|
|
* UIWS 2FA 이식: 1차 로그인 통과 후 발급하는 단기 verify-token.
|
|
* purpose=2fa 클레임으로 access 토큰과 구분(verify-token 으로는 보호 API 접근 불가).
|
|
*/
|
|
public String generateVerifyToken(String username, long validitySeconds) {
|
|
return Jwts.builder()
|
|
.subject(username)
|
|
.claim("purpose", "2fa")
|
|
.issuedAt(new Date())
|
|
.expiration(new Date(System.currentTimeMillis() + validitySeconds * 1000L))
|
|
.signWith(key())
|
|
.compact();
|
|
}
|
|
|
|
/** verify-token 검증 후 username 반환. 유효하지 않거나 purpose!=2fa 면 null. */
|
|
public String parseVerifyTokenUsername(String token) {
|
|
try {
|
|
Claims c = parse(token);
|
|
if (!"2fa".equals(c.get("purpose", String.class))) {
|
|
return null;
|
|
}
|
|
return c.getSubject();
|
|
} catch (JwtException | IllegalArgumentException e) {
|
|
log.debug("verify-token 검증 실패: {}", e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 보안: 토큰이 2FA verify-token(purpose=2fa)인지 판별.
|
|
* JwtFilter 가 access 토큰만 인증 컨텍스트로 인정하도록 verify-token 을 걸러내는 데 사용.
|
|
* verify-token 은 access 와 동일 서명키라 isValid() 는 통과 → 반드시 별도 차단(2FA 우회 방지).
|
|
*/
|
|
public boolean isVerifyToken(String token) {
|
|
try {
|
|
return "2fa".equals(parse(token).get("purpose", String.class));
|
|
} catch (JwtException | IllegalArgumentException e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public Claims parse(String token) {
|
|
return Jwts.parser().verifyWith(key()).build()
|
|
.parseSignedClaims(token).getPayload();
|
|
}
|
|
|
|
public boolean isValid(String token) {
|
|
try {
|
|
parse(token);
|
|
return true;
|
|
} catch (JwtException | IllegalArgumentException e) {
|
|
log.debug("JWT 검증 실패: {}", e.getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public String getUsername(String token) {
|
|
return parse(token).getSubject();
|
|
}
|
|
|
|
public String getRole(String token) {
|
|
return parse(token).get("role", String.class);
|
|
}
|
|
}
|