-
Notifications
You must be signed in to change notification settings - Fork 0
π Jwt Refresh #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
π Jwt Refresh #36
Changes from all commits
d34abc3
49b9c5f
7341b5b
2a4d71e
ed35dc5
230cb35
c63c7ff
608a2e9
d2e5305
f16eaec
c25e10d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package com.mycom.socket.auth.controller; | ||
|
|
||
| import com.mycom.socket.auth.config.JWTProperties; | ||
| import com.mycom.socket.auth.dto.response.TokenResponse; | ||
| import com.mycom.socket.auth.jwt.JWTUtil; | ||
| import com.mycom.socket.auth.security.CookieUtil; | ||
| import com.mycom.socket.global.exception.BadRequestException; | ||
| import io.jsonwebtoken.JwtException; | ||
| import jakarta.servlet.http.Cookie; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.Optional; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| public class RefreshController { | ||
|
|
||
| private final JWTUtil jwtUtil; | ||
| private final CookieUtil cookieUtil; | ||
| private final JWTProperties jwtProperties; | ||
|
|
||
|
|
||
| @PostMapping("/refresh") | ||
| public TokenResponse refreshAccessToken(HttpServletRequest request, HttpServletResponse response) { | ||
| Optional<String> refreshTokenOpt = extractRefreshToken(request); | ||
| if (refreshTokenOpt.isEmpty()) { | ||
| return TokenResponse.of("리νλ μ ν ν°μ΄ μμ΅λλ€. λ€μ λ‘κ·ΈμΈν΄μ£ΌμΈμ."); | ||
| } | ||
|
|
||
| String refreshToken = refreshTokenOpt.get(); | ||
| if (!jwtUtil.validateToken(refreshToken, "REFRESH_TOKEN")) { | ||
| response.addCookie(cookieUtil.createExpiredCookie(jwtProperties.getRefreshTokenCookieName())); | ||
| return TokenResponse.of("μ ν¨νμ§ μμ 리νλ μ ν ν°μ λλ€. λ€μ λ‘κ·ΈμΈν΄μ£ΌμΈμ."); | ||
| } | ||
|
|
||
| String email = jwtUtil.getEmail(refreshToken); | ||
| String newAccessToken = jwtUtil.createToken(email, jwtProperties.getAccessTokenValidityInSeconds(), "ACCESS_TOKEN"); | ||
| String newRefreshToken = jwtUtil.createToken(email, jwtProperties.getRefreshTokenValidityInSeconds(), "REFRESH_TOKEN"); | ||
|
|
||
| response.addCookie(cookieUtil.createAuthCookie(newAccessToken)); | ||
| response.addCookie(cookieUtil.createRefreshCookie(newRefreshToken)); | ||
|
|
||
|
Comment on lines
+41
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ Codebase verification ν ν° κ΄λ¦¬ 보μ μ·¨μ½μ νμΈλ¨ νμ¬ κ΅¬νμμ λ€μκ³Ό κ°μ 보μ μ·¨μ½μ μ΄ λ°κ²¬λμμ΅λλ€:
κΆμ₯ μ¬ν:
π Analysis chainν ν° μ¬λ°κΈ λ‘μ§ κ²μ¦ νμ μλ‘μ΄ ν ν° λ°κΈ μ λ€μ μ¬νλ€μ νμΈν΄μΌ ν©λλ€:
π Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Check for token revocation implementation
rg -l "TokenRevocationService|BlacklistService|InvalidatedTokenRepository"
Length of output: 76 Script: #!/bin/bash
# Search for token-related implementations with broader patterns
rg -l "token.*repository|token.*service|token.*cache|token.*store"
# Search for security configurations
rg -l "SecurityConfig|WebSecurityConfig|JwtConfig"
# Search for Redis or cache configurations
rg -l "RedisConfig|CacheConfig|TokenCache"
Length of output: 364 Script: #!/bin/bash
# Check Redis configuration implementation
cat src/main/java/com/mycom/socket/global/config/RedisConfig.java
# Check security configuration for token handling
cat src/main/java/com/mycom/socket/auth/config/SecurityConfig.java
# Search for Redis usage in token operations
rg -g "!*.{test,spec}.*" "redisTemplate|StringRedisTemplate" -A 3
Length of output: 7750 |
||
| return TokenResponse.of(newAccessToken); | ||
| } | ||
|
|
||
| private Optional<String> extractRefreshToken(HttpServletRequest request) { | ||
| if (request.getCookies() == null) { | ||
| return Optional.empty(); | ||
| } | ||
|
|
||
| return Arrays.stream(request.getCookies()) | ||
| .filter(cookie -> jwtProperties.getRefreshTokenCookieName().equals(cookie.getName())) | ||
| .map(Cookie::getValue) | ||
| .findFirst(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.mycom.socket.auth.dto.response; | ||
|
|
||
| public record TokenResponse( | ||
| String accessToken, | ||
| String message, | ||
| boolean success | ||
| ) { | ||
| public static TokenResponse of(String message) { | ||
| return new TokenResponse(null, message, false); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,9 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.mycom.socket.auth.jwt; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.mycom.socket.auth.config.JWTProperties; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.jsonwebtoken.ExpiredJwtException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.jsonwebtoken.JwtException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.jsonwebtoken.JwtParser; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.jsonwebtoken.Jwts; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.jsonwebtoken.security.Keys; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.extern.slf4j.Slf4j; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -18,53 +21,122 @@ public class JWTUtil { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final SecretKey secretKey; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final JWTProperties jwtProperties; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * JWTUtil μμ±μ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * μ€μ λ μν¬λ¦Ώ ν€λ₯Ό λ°νμΌλ‘ HMAC-SHA μκ³ λ¦¬μ¦μ© SecretKeyλ₯Ό μμ±ν©λλ€. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param jwtProperties JWT κ΄λ ¨ μ€μ κ°μ λ΄κ³ μλ νλ‘νΌν° κ°μ²΄ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public JWTUtil(JWTProperties jwtProperties) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.jwtProperties = jwtProperties; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.secretKey = Keys.hmacShaKeyFor( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jwtProperties.getSecret().getBytes(StandardCharsets.UTF_8) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * JWT Parser μμ± | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * ν ν° κ²μ¦ λ° μ 보 μΆμΆμ μ¬μ©λλ κ³΅ν΅ Parserλ₯Ό μμ±ν©λλ€. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return μ€μ λ JWT Parser κ°μ²΄ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private JwtParser createParser() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Jwts.parser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .verifyWith(secretKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requireIssuer(jwtProperties.getIssuer()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * JWT ν ν° μμ± | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * μ£Όμ΄μ§ μ΄λ©μΌκ³Ό μ ν¨κΈ°κ°μΌλ‘ μλ‘μ΄ JWTλ₯Ό μμ±ν©λλ€. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param email ν ν°μ ν¬ν¨λ μ¬μ©μ μ΄λ©μΌ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param validityInSeconds ν ν° μ ν¨ κΈ°κ° (μ΄) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param accessToken | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return μμ±λ JWT λ¬Έμμ΄ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @throws IllegalStateException ν ν° μμ± μ€ μ€λ₯ λ°μ μ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String createToken(String email) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String createToken(String email, long validityInSeconds, String accessToken) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Date now = new Date(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Date validity = new Date(now.getTime() + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (jwtProperties.getAccessTokenValidityInSeconds() * 1000)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Jwts.builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .issuer(jwtProperties.getIssuer()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .subject(email) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .issuedAt(now) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expiration(validity) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .signWith(secretKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .compact(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Date validity = new Date(now.getTime() + (validityInSeconds * 1000)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Jwts.builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .issuer(jwtProperties.getIssuer()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .subject(email) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .issuedAt(now) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .expiration(validity) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .claim("type", accessToken) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .signWith(secretKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .compact(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (JwtException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.error("ν ν° μμ± μ€ μ€λ₯κ° λ°μνμ΅λλ€.", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new IllegalStateException("ν ν° μμ± μ€ μ€λ₯κ° λ°μνμ΅λλ€.", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+61
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion ν ν° μμ± λ³΄μ κ°ν νμ ν ν° μμ± μ λ€μ 보μ κΈ°λ₯λ€μ μΆκ°ν΄μΌ ν©λλ€:
return Jwts.builder()
.issuer(jwtProperties.getIssuer())
.subject(email)
.issuedAt(now)
.expiration(validity)
.claim("type", accessToken)
+ .id(UUID.randomUUID().toString())
+ .notBefore(now)
+ .audience()
+ .add(accessToken.toLowerCase())
+ .and()
.signWith(secretKey)
.compact();π Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * ν ν° μ ν¨μ± κ²μ¦ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * μ£Όμ΄μ§ ν ν°μ΄ μ ν¨νμ§ κ²μ¬ν©λλ€. ν ν°μ μλͺ , λ§λ£ μ¬λΆ, λ°κΈμ λ±μ νμΈν©λλ€. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param token κ²μ¦ν JWT λ¬Έμμ΄ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return ν ν°μ΄ μ ν¨νλ©΄ true, κ·Έλ μ§ μμΌλ©΄ false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public boolean validateToken(String token) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!StringUtils.hasText(token)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public boolean validateToken(String token, String expectedType) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!StringUtils.hasText(token)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Jwts.parser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var claims = Jwts.parser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .verifyWith(secretKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .requireIssuer(jwtProperties.getIssuer()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .parseSignedClaims(token); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warn("JWT ν ν° κ²μ¦ μ€ν¨", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .parseSignedClaims(token) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .getPayload(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ν ν° νμ κ²μ¦ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String tokenType = claims.get("type", String.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!expectedType.equals(tokenType)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warn("μλͺ»λ ν ν° νμ μ λλ€. expected: {}, actual: {}", expectedType, tokenType); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new Date().before(claims.getExpiration()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (ExpiredJwtException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warn("λ§λ£λ JWT ν ν°μ λλ€."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (JwtException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warn("μ ν¨νμ§ μμ JWT ν ν°μ λλ€.", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+87
to
114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ Codebase verification ν ν° λ³΄μ κ°ν κΆμ₯μ¬ν νμΈ λ¦¬λ·° μ견μμ μ μλ 보μ κ°ν νλͺ©λ€μ΄ νμ¬ κ΅¬νλμ΄ μμ§ μμμ νμΈνμ΅λλ€. λ€μ μ¬νλ€μ ꡬνμ κΆμ₯λ립λλ€:
π Analysis chainν ν° κ²μ¦ λ‘μ§ κ°ν νμ λ€μ κ²μ¦ νλͺ©λ€μ μΆκ°ν΄μΌ ν©λλ€:
π Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Check for token blacklist implementation
rg -l "TokenBlacklist|RevokedToken|InvalidatedToken"
Length of output: 54 Script: #!/bin/bash
# Search for Redis/Cache configurations and JWT-related security implementations
rg -l "Redis|Cache|TokenStore"
# Search for JWT claim handling
rg -A 5 "\.claim\(|\.getClaim|jti|nbf"
# Search for security configuration files
fd -e java -e xml -e properties -e yml "Security|Auth|JWT" --type f
Length of output: 1424 Script: #!/bin/bash
# Check Redis service implementation for token operations
cat src/main/java/com/mycom/socket/global/service/RedisService.java
# Check security configuration
cat src/main/java/com/mycom/socket/auth/config/SecurityConfig.java
Length of output: 5402 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * ν ν°μμ μ΄λ©μΌ μΆμΆ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * ν ν°μ λ§λ£ μκ° μΆμΆ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param token JWT λ¬Έμμ΄ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return ν ν°μ λ§λ£ μκ° | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Date getExpirationFromToken(String token) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Jwts.parser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .verifyWith(secretKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .parseSignedClaims(token) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .getPayload() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .getExpiration(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * ν ν°μμ μ¬μ©μ μ΄λ©μΌ μΆμΆ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * JWTμ subject ν΄λ μμμ μ¬μ©μ μ΄λ©μΌμ μΆμΆν©λλ€. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param token JWT λ¬Έμμ΄ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return ν ν°μ ν¬ν¨λ μ¬μ©μ μ΄λ©μΌ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @throws IllegalStateException ν ν°μμ μ΄λ©μΌμ μΆμΆν μ μλ κ²½μ° | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String getEmail(String token) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Jwts.parser() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,26 +11,65 @@ public class CookieUtil { | |
| private final JWTProperties jwtProperties; | ||
|
|
||
| /** | ||
| * μΈμ¦ μΏ ν€ μμ± | ||
| * κ³΅ν΅ μΏ ν€ μμ± λ©μλ | ||
| * λͺ¨λ μ’ λ₯μ μΏ ν€ μμ±μ μ¬μ©λλ κΈ°λ³Έ λ©μλμ λλ€. | ||
| * | ||
| * @param name μΏ ν€μ μ΄λ¦ | ||
| * @param value μΏ ν€μ μ μ₯λ κ° (ν ν°) | ||
| * @param maxAge μΏ ν€μ μ ν¨ μκ° (μ΄ λ¨μ) | ||
| * @param secure HTTPS νλ‘ν μ½μμλ§ μ μ‘ μ¬λΆ | ||
| * @return μμ±λ μΏ ν€ κ°μ²΄ | ||
| */ | ||
| public Cookie createAuthCookie(String token) { | ||
| Cookie cookie = new Cookie(jwtProperties.getCookieName(), token); | ||
| private Cookie createCookie(String name, String value, long maxAge, boolean secure) { | ||
| Cookie cookie = new Cookie(name, value); | ||
| cookie.setHttpOnly(true); | ||
| cookie.setSecure(jwtProperties.isSecureCookie()); | ||
| cookie.setPath("/"); | ||
| cookie.setMaxAge((int) jwtProperties.getAccessTokenValidityInSeconds()); | ||
| cookie.setSecure(secure); | ||
| cookie.setPath("/api/auth"); | ||
| cookie.setMaxAge((int) maxAge); | ||
| cookie.setAttribute("SameSite", "Strict"); //CSRF 곡격 λ°©μ§ μ€μ μΆκ° | ||
| return cookie; | ||
| } | ||
|
|
||
| /** | ||
| * μΈμ¦ μΏ ν€ λ§λ£ μ²λ¦¬ | ||
| * Access Tokenμ μ μ₯νλ μΏ ν€ μμ± | ||
| * ν΄λΌμ΄μΈνΈ μΈμ¦μ μ¬μ©λλ Access Tokenμ μΏ ν€μ μ μ₯ν©λλ€. | ||
| * | ||
| * @param token JWT Access Token λ¬Έμμ΄ | ||
| * @return Access Tokenμ΄ μ μ₯λ μΏ ν€ | ||
| */ | ||
| public Cookie createExpiredAuthCookie() { | ||
| Cookie cookie = new Cookie(jwtProperties.getCookieName(), null); | ||
| cookie.setHttpOnly(true); | ||
| cookie.setSecure(true); | ||
| cookie.setPath("/"); | ||
| cookie.setMaxAge(0); // μ¦μ λ§λ£ | ||
| return cookie; | ||
| public Cookie createAuthCookie(String token) { | ||
| return createCookie( | ||
| jwtProperties.getAccessTokenCookieName(), | ||
| token, | ||
| jwtProperties.getAccessTokenValidityInSeconds(), | ||
| jwtProperties.isSecureCookie() | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Refresh Tokenμ μ μ₯νλ μΏ ν€ μμ± | ||
| * Access Token μ¬λ°κΈμ μ¬μ©λλ Refresh Tokenμ μΏ ν€μ μ μ₯ν©λλ€. | ||
| * | ||
| * @param token JWT Refresh Token λ¬Έμμ΄ | ||
| * @return Refresh Tokenμ΄ μ μ₯λ μΏ ν€ | ||
| */ | ||
| public Cookie createRefreshCookie(String token) { | ||
| return createCookie( | ||
| jwtProperties.getRefreshTokenCookieName(), | ||
| token, | ||
| jwtProperties.getRefreshTokenValidityInSeconds(), | ||
| jwtProperties.isSecureCookie() | ||
| ); | ||
| } | ||
|
Comment on lines
+49
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ Codebase verification ν ν° μ ν¨κΈ°κ° κ²μ¦ λ‘μ§ κ΅¬ν λ°©μ 리νλ μ ν ν°μ μ ν¨ κΈ°κ°μ΄ μ‘μΈμ€ ν ν°λ³΄λ€ κΈΈλλ‘ λ³΄μ₯νκΈ° μν΄ λ€μκ³Ό κ°μ κ²μ¦ λ‘μ§ μΆκ°λ₯Ό μ μλ립λλ€:
π Analysis chain리νλ μ ν ν° μ ν¨ κΈ°κ° κ²μ¦ μΆκ° κ³ λ € 리νλ μ ν ν°μ μ ν¨ κΈ°κ°μ΄ μ‘μΈμ€ ν ν°λ³΄λ€ κΈΈκ² μ€μ λμλμ§ νμΈνλ κ²μ¦ λ‘μ§ μΆκ°λ₯Ό κ³ λ €ν΄λ³΄μΈμ. π Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# JWTPropertiesμμ ν ν° μ ν¨ κΈ°κ° μ€μ μ νμΈ
rg "tokenValidityInSeconds|refreshTokenValidityInSeconds" -A 2
Length of output: 383 Script: #!/bin/bash
# Get complete JWTProperties class
cat src/main/java/com/mycom/socket/auth/config/JWTProperties.java
# Check application properties/yaml files
fd -e yml -e yaml -e properties --exec cat {}
Length of output: 1162 |
||
|
|
||
| /** | ||
| * λ§λ£λ μΏ ν€ μμ± | ||
| * λ‘κ·Έμμ λλ ν ν° λ¬΄ν¨ν μ κΈ°μ‘΄ μΏ ν€λ₯Ό λ§λ£μν€κΈ° μν΄ μ¬μ©λ©λλ€. | ||
| * | ||
| * @param name λ§λ£μν¬ μΏ ν€μ μ΄λ¦ | ||
| * @return μ¦μ λ§λ£λλλ‘ μ€μ λ μΏ ν€ | ||
| */ | ||
| public Cookie createExpiredCookie(String name) { | ||
| return createCookie(name, null, 0, true); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| package com.mycom.socket.auth.security; | ||
|
|
||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.mycom.socket.auth.config.JWTProperties; | ||
| import com.mycom.socket.auth.jwt.JWTUtil; | ||
| import com.mycom.socket.global.dto.ApiResponse; | ||
| import com.mycom.socket.auth.dto.request.LoginRequest; | ||
|
|
@@ -28,6 +29,7 @@ public class LoginFilter extends UsernamePasswordAuthenticationFilter { | |
| private final AuthenticationManager authenticationManager; | ||
| private final CookieUtil cookieUtil; | ||
| private final ObjectMapper objectMapper; | ||
| private final JWTProperties jwtProperties; | ||
|
|
||
| @Override | ||
| public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) | ||
|
|
@@ -51,11 +53,23 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR | |
| MemberDetails memberDetails = (MemberDetails) authResult.getPrincipal(); | ||
| Member member = memberDetails.getMember(); | ||
|
|
||
| String token = jwtUtil.createToken(member.getEmail()); | ||
| // JWT ν ν° μμ± | ||
| String accessToken = jwtUtil.createToken( | ||
| member.getEmail(), | ||
| jwtProperties.getAccessTokenValidityInSeconds(), | ||
| "ACCESS_TOKEN" | ||
| ); | ||
| String refreshToken = jwtUtil.createToken( | ||
| member.getEmail(), | ||
| jwtProperties.getRefreshTokenValidityInSeconds(), | ||
| "REFRESH_TOKEN" | ||
| ); | ||
|
|
||
| // μΏ ν€ μμ± λ° μ€μ | ||
| Cookie authCookie = cookieUtil.createAuthCookie(token); | ||
| response.addCookie(authCookie); | ||
| Cookie accessTokenCookie = cookieUtil.createAuthCookie(accessToken); //μ‘μΈμ€ ν ν° μΏ ν€ | ||
| Cookie refreshTokenCookie = cookieUtil.createRefreshCookie(refreshToken); //리νλ μ ν ν° μΏ ν€ | ||
| response.addCookie(accessTokenCookie); | ||
| response.addCookie(refreshTokenCookie); | ||
|
Comment on lines
+69
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ Codebase verification μΏ ν€ λ³΄μ μ€μ μ΄ λΆμμ ν©λλ€. λ€μκ³Ό κ°μ 보μ λ¬Έμ κ° λ°κ²¬λμμ΅λλ€:
μμ μ΄ νμν νμΌ:
κΆμ₯ μ¬ν:
π Analysis chainμΏ ν€ λ³΄μ μ€μ μ νμΈν΄μ£ΌμΈμ. μΏ ν€ μμ± μ λ€μ 보μ μμ±λ€μ΄ μ¬λ°λ₯΄κ² μ€μ λμ΄ μλμ§ νμΈμ΄ νμν©λλ€:
π Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# CookieUtilμ ꡬνμ νμΈνμ¬ λ³΄μ μ€μ κ²μ¦
rg -A 10 "createAuthCookie|createRefreshCookie" --type java
Length of output: 8548 Script: #!/bin/bash
# Check createCookie implementation and JwtProperties
echo "=== CookieUtil.createCookie implementation ==="
ast-grep --pattern 'createCookie($$$) { $$$ }'
echo -e "\n=== JwtProperties configuration ==="
rg -A 5 "class JwtProperties" --type java
Length of output: 282 Script: #!/bin/bash
# μΏ ν€ μμ± λ©μλμ μ€μ νμΌ κ²μ
echo "=== Cookie creation implementation ==="
rg -A 15 "private.*createCookie" --type java
echo -e "\n=== Security and JWT configuration ==="
fd -e yml -e properties -e yaml | xargs rg -l "jwt|cookie|secure"
Length of output: 1755 |
||
|
|
||
| // λ‘κ·ΈμΈ μλ΅ μμ± | ||
| LoginResponse loginResponse = new LoginResponse(member.getEmail(), member.getNickname()); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
νμ μμ±μ λν μ ν¨μ± κ²μ¦ μΆκ° νμ
ν ν° μ ν¨ κΈ°κ°κ³Ό μΏ ν€ μ΄λ¦μ νμ κ°μ΄λ―λ‘, μ΄μ λν μ ν¨μ± κ²μ¦μ΄ νμν©λλ€.
λ€μκ³Ό κ°μ΄ μμ νλ κ²μ μ μν©λλ€:
π Committable suggestion