Skip to content

Commit 7fabe93

Browse files
authored
mrege : 커스텀 JWT Provider 구현
Feat : 커스텀 JWT Provider 구현
2 parents dd04994 + b8d8059 commit 7fabe93

File tree

12 files changed

+115
-24
lines changed

12 files changed

+115
-24
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.terning.terningserver.auth.dto;
2+
3+
public record Token(String accessToken, String refreshToken) {
4+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.terning.terningserver.auth.jwt;
2+
3+
import io.jsonwebtoken.Claims;
4+
import io.jsonwebtoken.ExpiredJwtException;
5+
import io.jsonwebtoken.Jwts;
6+
import io.jsonwebtoken.MalformedJwtException;
7+
import io.jsonwebtoken.UnsupportedJwtException;
8+
import io.jsonwebtoken.security.Keys;
9+
import io.jsonwebtoken.security.SecurityException;
10+
import jakarta.annotation.PostConstruct;
11+
import lombok.RequiredArgsConstructor;
12+
import org.springframework.stereotype.Component;
13+
import org.terning.terningserver.auth.dto.Token;
14+
import org.terning.terningserver.auth.jwt.exception.JwtErrorCode;
15+
import org.terning.terningserver.auth.jwt.exception.JwtException;
16+
import org.terning.terningserver.common.config.ValueConfig;
17+
18+
19+
import javax.crypto.SecretKey;
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.Date;
22+
23+
@Component
24+
@RequiredArgsConstructor
25+
public class JwtProvider {
26+
27+
private static final String USER_ID_CLAIM = "userId";
28+
private static final String TOKEN_PREFIX = "Bearer ";
29+
30+
private final ValueConfig valueConfig;
31+
private SecretKey secretKey;
32+
33+
@PostConstruct
34+
protected void init() {
35+
secretKey = Keys.hmacShaKeyFor(valueConfig.getSecretKey().getBytes(StandardCharsets.UTF_8));
36+
}
37+
38+
public Token generateTokens(Long userId) {
39+
String accessToken = generateToken(userId, valueConfig.getAccessTokenExpired());
40+
String refreshToken = generateToken(userId, valueConfig.getRefreshTokenExpired());
41+
return new Token(accessToken, refreshToken);
42+
}
43+
44+
public Token generateAccessToken(Long userId) {
45+
String accessToken = generateToken(userId, valueConfig.getAccessTokenExpired());
46+
return new Token(accessToken, null);
47+
}
48+
49+
public Long getUserIdFrom(String authorizationHeader) {
50+
String token = resolveToken(authorizationHeader);
51+
52+
Claims claims = parseClaims(token);
53+
54+
Object userIdClaim = claims.get(USER_ID_CLAIM);
55+
if (userIdClaim instanceof Number) {
56+
return ((Number) userIdClaim).longValue();
57+
}
58+
throw new JwtException(JwtErrorCode.INVALID_USER_ID_TYPE);
59+
}
60+
61+
public String resolveToken(String rawToken) {
62+
if (rawToken != null && rawToken.startsWith(TOKEN_PREFIX)) {
63+
return rawToken.substring(TOKEN_PREFIX.length());
64+
}
65+
throw new JwtException(JwtErrorCode.TOKEN_NOT_FOUND);
66+
}
67+
68+
private String generateToken(Long userId, long expiration) {
69+
Claims claims = Jwts.claims();
70+
claims.put(USER_ID_CLAIM, userId);
71+
72+
return Jwts.builder()
73+
.setClaims(claims)
74+
.setIssuedAt(new Date())
75+
.setExpiration(new Date(System.currentTimeMillis() + expiration))
76+
.signWith(secretKey)
77+
.compact();
78+
}
79+
80+
private Claims parseClaims(String token) {
81+
try {
82+
return Jwts.parserBuilder()
83+
.setSigningKey(secretKey)
84+
.build()
85+
.parseClaimsJws(token)
86+
.getBody();
87+
} catch (ExpiredJwtException e) {
88+
throw new JwtException(JwtErrorCode.EXPIRED_JWT_TOKEN);
89+
} catch (UnsupportedJwtException | MalformedJwtException | SecurityException | IllegalArgumentException e) {
90+
throw new JwtException(JwtErrorCode.INVALID_JWT_TOKEN);
91+
}
92+
}
93+
}

src/main/java/org/terning/terningserver/common/security/jwt/exception/JwtErrorCode.java renamed to src/main/java/org/terning/terningserver/auth/jwt/exception/JwtErrorCode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.terning.terningserver.common.security.jwt.exception;
1+
package org.terning.terningserver.auth.jwt.exception;
22

33
import lombok.AllArgsConstructor;
44
import lombok.Getter;
@@ -11,6 +11,8 @@ public enum JwtErrorCode {
1111
INVALID_USER_ID(HttpStatus.BAD_REQUEST, "유효하지 않은 userId 값입니다."),
1212
INVALID_USER_ID_TYPE(HttpStatus.BAD_REQUEST, "유효하지 않은 userId 타입입니다."),
1313
INVALID_USER_DETAILS_TYPE(HttpStatus.INTERNAL_SERVER_ERROR, "유효하지 않은 UserDetail 타입입니다."),
14+
TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "Authorization 헤더에 토큰이 없습니다."),
15+
EXPIRED_JWT_TOKEN(HttpStatus.UNAUTHORIZED, "만료된 JWT 토큰입니다."),
1416
;
1517

1618
public static final String PREFIX = "[JWT ERROR]";

src/main/java/org/terning/terningserver/common/security/jwt/exception/JwtException.java renamed to src/main/java/org/terning/terningserver/auth/jwt/exception/JwtException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.terning.terningserver.common.security.jwt.exception;
1+
package org.terning.terningserver.auth.jwt.exception;
22

33
import lombok.Getter;
44

src/main/java/org/terning/terningserver/common/config/ValueConfig.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package org.terning.terningserver.common.config;
22

3-
import jakarta.annotation.PostConstruct;
43
import lombok.Getter;
54
import org.springframework.beans.factory.annotation.Value;
65
import org.springframework.context.annotation.Configuration;
76

8-
import java.nio.charset.StandardCharsets;
9-
import java.util.Base64;
10-
117
@Configuration
128
@Getter
139
public class ValueConfig {
@@ -26,9 +22,4 @@ public class ValueConfig {
2622

2723
@Value("${jwt.refresh-token-expired}")
2824
private Long refreshTokenExpired;
29-
30-
@PostConstruct
31-
protected void init() {
32-
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8));
33-
}
34-
}
25+
}

src/main/java/org/terning/terningserver/common/exception/GlobalExceptionHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
import org.terning.terningserver.auth.common.exception.AuthException;
1414
import org.terning.terningserver.common.exception.dto.ErrorResponse;
1515
import org.terning.terningserver.common.exception.enums.ErrorMessage;
16-
import org.terning.terningserver.common.security.jwt.exception.JwtErrorCode;
17-
import org.terning.terningserver.common.security.jwt.exception.JwtException;
16+
import org.terning.terningserver.auth.jwt.exception.JwtErrorCode;
17+
import org.terning.terningserver.auth.jwt.exception.JwtException;
1818

1919
@RestControllerAdvice
2020
@Slf4j

src/main/java/org/terning/terningserver/common/security/jwt/application/JwtClaimsGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import lombok.RequiredArgsConstructor;
77
import org.springframework.security.core.Authentication;
88
import org.springframework.stereotype.Service;
9-
import org.terning.terningserver.common.security.jwt.exception.JwtErrorCode;
9+
import org.terning.terningserver.auth.jwt.exception.JwtErrorCode;
1010

1111
import java.util.Map;
1212

src/main/java/org/terning/terningserver/common/security/jwt/application/JwtUserIdExtractor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import io.jsonwebtoken.Claims;
44
import lombok.RequiredArgsConstructor;
55
import org.springframework.stereotype.Component;
6-
import org.terning.terningserver.common.security.jwt.exception.JwtErrorCode;
7-
import org.terning.terningserver.common.security.jwt.exception.JwtException;
6+
import org.terning.terningserver.auth.jwt.exception.JwtErrorCode;
7+
import org.terning.terningserver.auth.jwt.exception.JwtException;
88
import org.terning.terningserver.common.security.jwt.auth.JwtClaimsParser;
99

1010
@Component

src/main/java/org/terning/terningserver/common/security/jwt/auth/JwtClaimsParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import lombok.RequiredArgsConstructor;
66
import org.springframework.stereotype.Service;
77
import org.terning.terningserver.common.config.ValueConfig;
8-
import org.terning.terningserver.common.security.jwt.exception.JwtErrorCode;
9-
import org.terning.terningserver.common.security.jwt.exception.JwtException;
8+
import org.terning.terningserver.auth.jwt.exception.JwtErrorCode;
9+
import org.terning.terningserver.auth.jwt.exception.JwtException;
1010
import org.terning.terningserver.common.security.jwt.provider.JwtKeyProvider;
1111

1212
@Service

src/main/java/org/terning/terningserver/common/security/jwt/auth/UserIdConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.terning.terningserver.common.security.jwt.auth;
22

3-
import org.terning.terningserver.common.security.jwt.exception.JwtErrorCode;
4-
import org.terning.terningserver.common.security.jwt.exception.JwtException;
3+
import org.terning.terningserver.auth.jwt.exception.JwtErrorCode;
4+
import org.terning.terningserver.auth.jwt.exception.JwtException;
55

66
public class UserIdConverter {
77

0 commit comments

Comments
 (0)