Skip to content

Commit cbddbae

Browse files
authored
[deploy] 재발급 원자성 처리 및 CHIPS 제거 배포 환경에 반영
[deploy] 재발급 원자성 처리 및 CHIPS 제거 배포 환경에 반영
2 parents ecd71fb + c4634e9 commit cbddbae

3 files changed

Lines changed: 33 additions & 30 deletions

File tree

‎src/main/java/com/Timo/Timo/global/auth/service/AuthService.java‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.Timo.Timo.global.auth.service;
22

3-
import com.Timo.Timo.domain.calendar.client.GoogleOAuthClient;
43
import com.Timo.Timo.domain.calendar.entity.CalendarRevocationOutbox;
54
import com.Timo.Timo.domain.calendar.repository.CalendarConnectionRepository;
65
import com.Timo.Timo.domain.calendar.repository.CalendarRevocationOutboxRepository;
@@ -81,12 +80,10 @@ public ReissueResult reissue(String refreshToken, String sessionId) {
8180
throw new CustomException(UserErrorCode.USER_NOT_FOUND);
8281
}
8382

84-
if (!refreshTokenService.isRefreshTokenValid(String.valueOf(userId), sessionId, refreshToken)){
83+
if (!refreshTokenService.validateAndConsumeRefreshToken(String.valueOf(userId), sessionId, refreshToken)) {
8584
throw new CustomException(AuthErrorCode.INVALID_REFRESH_TOKEN);
8685
}
8786

88-
refreshTokenService.deleteRefreshToken(String.valueOf(userId), sessionId);
89-
9087
String newAccessToken = jwtTokenProvider.generateAccessToken(userId);
9188
String newRefreshToken = jwtTokenProvider.generateRefreshToken(userId);
9289
String newSessionId = refreshTokenService.saveRefreshToken(String.valueOf(userId), newRefreshToken);

‎src/main/java/com/Timo/Timo/global/auth/service/RefreshTokenService.java‎

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import com.Timo.Timo.global.jwt.provider.JwtTokenProvider;
44
import java.util.ArrayList;
55
import java.util.List;
6-
import java.util.Objects;
7-
import java.util.Set;
86
import java.util.UUID;
97
import java.util.concurrent.TimeUnit;
108
import lombok.RequiredArgsConstructor;
119
import org.springframework.data.redis.core.Cursor;
1210
import org.springframework.data.redis.core.RedisTemplate;
1311
import org.springframework.data.redis.core.ScanOptions;
12+
import org.springframework.data.redis.core.script.DefaultRedisScript;
13+
import org.springframework.data.redis.core.script.RedisScript;
1414
import org.springframework.stereotype.Service;
1515

1616
@Service
@@ -22,23 +22,30 @@ public class RefreshTokenService {
2222

2323
private static final String KEY_PREFIX = "refresh:";
2424

25+
private static final RedisScript<Long> COMPARE_AND_DELETE_SCRIPT = new DefaultRedisScript<>(
26+
"local stored = redis.call('GET', KEYS[1]) "
27+
+ "if stored == ARGV[1] then "
28+
+ " redis.call('DEL', KEYS[1]) "
29+
+ " return 1 "
30+
+ "else "
31+
+ " return 0 "
32+
+ "end",
33+
Long.class
34+
);
35+
2536
public String saveRefreshToken(String userId, String refreshToken){
2637
String sessionId = UUID.randomUUID().toString();
2738
redisTemplate.opsForValue().set(
28-
KEY_PREFIX + userId + ":" + sessionId,
39+
buildKey(userId, sessionId),
2940
refreshToken,
3041
jwtTokenProvider.getRefreshTokenExpiry(),
3142
TimeUnit.SECONDS
3243
);
3344
return sessionId;
3445
}
3546

36-
public String getRefreshToken(String userId, String sessionId) {
37-
return redisTemplate.opsForValue().get(KEY_PREFIX + userId + ":" + sessionId);
38-
}
39-
4047
public void deleteRefreshToken(String userId, String sessionId) {
41-
redisTemplate.delete(KEY_PREFIX + userId + ":" + sessionId);
48+
redisTemplate.delete(buildKey(userId, sessionId));
4249
}
4350

4451
public void deleteAllRefreshTokens(String userId) {
@@ -60,7 +67,16 @@ public void deleteAllRefreshTokens(String userId) {
6067
}
6168
}
6269

63-
public boolean isRefreshTokenValid(String userId, String sessionId, String refreshToken) {
64-
return Objects.equals(refreshToken, getRefreshToken(userId, sessionId));
70+
public boolean validateAndConsumeRefreshToken(String userId, String sessionId, String refreshToken) {
71+
Long result = redisTemplate.execute(
72+
COMPARE_AND_DELETE_SCRIPT,
73+
List.of(buildKey(userId, sessionId)),
74+
refreshToken
75+
);
76+
return Long.valueOf(1L).equals(result);
77+
}
78+
79+
private String buildKey(String userId, String sessionId) {
80+
return KEY_PREFIX + userId + ":" + sessionId;
6581
}
6682
}

‎src/main/java/com/Timo/Timo/global/auth/utils/CookieUtil.java‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,22 @@
66
public class CookieUtil {
77

88
public static ResponseCookie createCookie(String name, String value, long maxAgeSeconds, boolean secure) {
9-
ResponseCookie.ResponseCookieBuilder builder = ResponseCookie.from(name, value)
9+
return ResponseCookie.from(name, value)
1010
.httpOnly(true)
1111
.secure(secure)
1212
.path("/api/v1/auth")
1313
.maxAge(Duration.ofSeconds(maxAgeSeconds))
14-
.sameSite(secure ? "None" : "Strict");
15-
16-
if (secure) {
17-
builder.partitioned(true);
18-
}
19-
20-
return builder.build();
14+
.sameSite(secure ? "None" : "Strict")
15+
.build();
2116
}
2217

2318
public static ResponseCookie expireCookie(String name, boolean secure) {
24-
ResponseCookie.ResponseCookieBuilder builder = ResponseCookie.from(name, "")
19+
return ResponseCookie.from(name, "")
2520
.httpOnly(true)
2621
.secure(secure)
2722
.path("/api/v1/auth")
2823
.maxAge(0)
29-
.sameSite(secure ? "None" : "Strict");
30-
31-
if (secure) {
32-
builder.partitioned(true);
33-
}
34-
35-
return builder.build();
24+
.sameSite(secure ? "None" : "Strict")
25+
.build();
3626
}
3727
}

0 commit comments

Comments
 (0)