From 8a02476d1725b1eb27ee2f555dad41b1a0890a0f Mon Sep 17 00:00:00 2001 From: seokhwan-an Date: Tue, 19 Sep 2023 09:13:29 +0900 Subject: [PATCH 1/5] =?UTF-8?q?refactor:=20refreshToken=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=EB=A7=8C=20accessToken=EC=9D=84=20=EC=9E=AC=EB=B0=9C=EA=B8=89?= =?UTF-8?q?=ED=95=B4=EC=A3=BC=EB=8D=98=20=EB=B0=A9=EC=8B=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 세부사항 - inMemoryTokenPairRepository 도입 --- .../shook/auth/application/AuthService.java | 13 +++-- .../shook/auth/exception/TokenException.java | 22 ++++++++ .../InMemoryTokenPairRepository.java | 30 +++++++++++ .../auth/ui/AccessTokenReissueController.java | 12 +++-- .../ui/openapi/AccessTokenReissueApi.java | 22 ++++++-- .../shook/globalexception/ErrorCode.java | 2 + .../auth/application/AuthServiceTest.java | 30 +++++++---- .../InMemoryTokenPairRepositoryTest.java | 50 +++++++++++++++++++ .../ui/AccessTokenReissueControllerTest.java | 17 +++++-- .../ControllerAdviceTest.java | 2 + 10 files changed, 171 insertions(+), 29 deletions(-) create mode 100644 backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java create mode 100644 backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java diff --git a/backend/src/main/java/shook/shook/auth/application/AuthService.java b/backend/src/main/java/shook/shook/auth/application/AuthService.java index ef25d06c4..60afb42bb 100644 --- a/backend/src/main/java/shook/shook/auth/application/AuthService.java +++ b/backend/src/main/java/shook/shook/auth/application/AuthService.java @@ -7,9 +7,9 @@ import shook.shook.auth.application.dto.GoogleMemberInfoResponse; import shook.shook.auth.application.dto.ReissueAccessTokenResponse; import shook.shook.auth.application.dto.TokenPair; +import shook.shook.auth.repository.InMemoryTokenPairRepository; import shook.shook.member.application.MemberService; import shook.shook.member.domain.Member; -import shook.shook.member.domain.Nickname; @RequiredArgsConstructor @Service @@ -18,6 +18,7 @@ public class AuthService { private final MemberService memberService; private final GoogleInfoProvider googleInfoProvider; private final TokenProvider tokenProvider; + private final InMemoryTokenPairRepository inMemoryTokenPairRepository; public TokenPair login(final String authorizationCode) { final GoogleAccessTokenResponse accessTokenResponse = @@ -34,16 +35,18 @@ public TokenPair login(final String authorizationCode) { final String nickname = member.getNickname(); final String accessToken = tokenProvider.createAccessToken(memberId, nickname); final String refreshToken = tokenProvider.createRefreshToken(memberId, nickname); + inMemoryTokenPairRepository.add(refreshToken, accessToken); return new TokenPair(accessToken, refreshToken); } - public ReissueAccessTokenResponse reissueAccessTokenByRefreshToken(final String refreshToken) { + public ReissueAccessTokenResponse reissueAccessTokenByRefreshToken(final String refreshToken, final String accessToken) { final Claims claims = tokenProvider.parseClaims(refreshToken); final Long memberId = claims.get("memberId", Long.class); final String nickname = claims.get("nickname", String.class); - memberService.findByIdAndNicknameThrowIfNotExist(memberId, new Nickname(nickname)); - final String accessToken = tokenProvider.createAccessToken(memberId, nickname); - return new ReissueAccessTokenResponse(accessToken); + inMemoryTokenPairRepository.validateTokenPair(refreshToken, accessToken); + final String reissuedAccessToken = tokenProvider.createAccessToken(memberId, nickname); + inMemoryTokenPairRepository.update(refreshToken, reissuedAccessToken); + return new ReissueAccessTokenResponse(reissuedAccessToken); } } diff --git a/backend/src/main/java/shook/shook/auth/exception/TokenException.java b/backend/src/main/java/shook/shook/auth/exception/TokenException.java index f9a902bbd..dd878627d 100644 --- a/backend/src/main/java/shook/shook/auth/exception/TokenException.java +++ b/backend/src/main/java/shook/shook/auth/exception/TokenException.java @@ -38,4 +38,26 @@ public ExpiredTokenException(final Map inputValuesByProperty) { super(ErrorCode.EXPIRED_TOKEN, inputValuesByProperty); } } + + public static class RefreshTokenNotFoundException extends TokenException { + + public RefreshTokenNotFoundException() { + super(ErrorCode.INVALID_REFRESH_TOKEN); + } + + public RefreshTokenNotFoundException(final Map inputValuesByProperty) { + super(ErrorCode.INVALID_REFRESH_TOKEN, inputValuesByProperty); + } + } + + public static class TokenPairNotMatchingException extends TokenException { + + public TokenPairNotMatchingException() { + super(ErrorCode.TOKEN_PAIR_NOT_MATCHING_EXCEPTION); + } + + public TokenPairNotMatchingException(final Map inputValuesByProperty) { + super(ErrorCode.TOKEN_PAIR_NOT_MATCHING_EXCEPTION, inputValuesByProperty); + } + } } diff --git a/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java b/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java new file mode 100644 index 000000000..f32c8bf09 --- /dev/null +++ b/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java @@ -0,0 +1,30 @@ +package shook.shook.auth.repository; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.springframework.stereotype.Repository; +import shook.shook.auth.exception.TokenException; +import shook.shook.auth.exception.TokenException.TokenPairNotMatchingException; + +@Repository +public class InMemoryTokenPairRepository { + + private final Map tokenPairs = new ConcurrentHashMap<>(); + + public void validateTokenPair(final String refreshToken, final String accessToken) { + if (!tokenPairs.containsKey(refreshToken)) { + throw new TokenException.RefreshTokenNotFoundException(Map.of("wrongRefreshToken", refreshToken)); + } + if (!tokenPairs.get(refreshToken).equals(accessToken)) { + throw new TokenPairNotMatchingException(Map.of("wrongAccessToken", accessToken)); + } + } + + public void add(final String refreshToken, final String accessToken) { + tokenPairs.put(refreshToken, accessToken); + } + + public void update(final String refreshToken, final String accessToken) { + tokenPairs.put(refreshToken, accessToken); + } +} diff --git a/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java b/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java index 2e45b4f40..659c242e0 100644 --- a/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java +++ b/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java @@ -3,7 +3,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; import shook.shook.auth.application.AuthService; import shook.shook.auth.application.dto.ReissueAccessTokenResponse; @@ -16,18 +17,21 @@ public class AccessTokenReissueController implements AccessTokenReissueApi { private static final String EMPTY_REFRESH_TOKEN = "none"; private static final String REFRESH_TOKEN_KEY = "refreshToken"; + private static final String TOKEN_PREFIX = "Bearer "; private final AuthService authService; - @GetMapping("/reissue") + @PostMapping("/reissue") public ResponseEntity reissueAccessToken( - @CookieValue(value = REFRESH_TOKEN_KEY, defaultValue = EMPTY_REFRESH_TOKEN) final String refreshToken + @CookieValue(value = REFRESH_TOKEN_KEY, defaultValue = EMPTY_REFRESH_TOKEN) final String refreshToken, + @RequestHeader("Authorization") final String authorization ) { if (refreshToken.equals(EMPTY_REFRESH_TOKEN)) { throw new AuthorizationException.RefreshTokenNotFoundException(); } + final String accessToken = authorization.split(TOKEN_PREFIX)[1]; final ReissueAccessTokenResponse response = - authService.reissueAccessTokenByRefreshToken(refreshToken); + authService.reissueAccessTokenByRefreshToken(accessToken, refreshToken); return ResponseEntity.ok(response); } diff --git a/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java b/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java index 17751f063..21f2c0375 100644 --- a/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java +++ b/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java @@ -2,10 +2,12 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; import shook.shook.auth.application.dto.ReissueAccessTokenResponse; @Tag(name = "AccessTokenReissue", description = "액세스 토큰 재발급 API") @@ -19,13 +21,23 @@ public interface AccessTokenReissueApi { responseCode = "200", description = "액세스 토큰 재발급 성공" ) - @Parameter( - name = "refreshToken", - description = "리프레시 토큰", - required = true + @Parameters( + value = { + @Parameter( + name = "refreshToken", + description = "리프레시 토큰", + required = true + ), + @Parameter( + name = "authorization", + description = "authorization 헤더", + required = true + ) + } ) @GetMapping("/reissue") ResponseEntity reissueAccessToken( - final String refreshToken + final String refreshToken, + @RequestHeader("Authorization") final String authorization ); } diff --git a/backend/src/main/java/shook/shook/globalexception/ErrorCode.java b/backend/src/main/java/shook/shook/globalexception/ErrorCode.java index 3b29b2fa8..638a75a1b 100644 --- a/backend/src/main/java/shook/shook/globalexception/ErrorCode.java +++ b/backend/src/main/java/shook/shook/globalexception/ErrorCode.java @@ -18,6 +18,8 @@ public enum ErrorCode { REFRESH_TOKEN_NOT_FOUND_EXCEPTION(1006, "accessToken 을 재발급하기 위해서는 refreshToken 이 필요합니다."), ACCESS_TOKEN_NOT_FOUND(1007, "accessToken이 필요합니다."), UNAUTHENTICATED_EXCEPTION(1008, "권한이 없는 요청입니다."), + INVALID_REFRESH_TOKEN(1009, "존재하지 않는 refreshToken 입니다."), + TOKEN_PAIR_NOT_MATCHING_EXCEPTION(1010, "올바르지 않은 TokenPair 입니다."), // 2000: 킬링파트 - 좋아요, 댓글 diff --git a/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java b/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java index 4c112efec..c1666eeb2 100644 --- a/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java +++ b/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -17,6 +18,7 @@ import shook.shook.auth.application.dto.ReissueAccessTokenResponse; import shook.shook.auth.application.dto.TokenPair; import shook.shook.auth.exception.TokenException; +import shook.shook.auth.repository.InMemoryTokenPairRepository; import shook.shook.member.application.MemberService; import shook.shook.member.domain.Member; import shook.shook.member.domain.repository.MemberRepository; @@ -35,8 +37,15 @@ class AuthServiceTest { @Autowired private MemberService memberService; + @Autowired + private InMemoryTokenPairRepository inMemoryTokenPairRepository; + private TokenProvider tokenProvider; + private String refreshToken; + + private String accessToken; + private AuthService authService; @BeforeEach @@ -45,8 +54,12 @@ void setUp() { 100000L, 1000000L, "asdfsdsvsdf2esvsdvsdvs23"); - authService = new AuthService(memberService, googleInfoProvider, tokenProvider); savedMember = memberRepository.save(new Member("shook@wooteco.com", "shook")); + refreshToken = tokenProvider.createRefreshToken(savedMember.getId(), savedMember.getNickname()); + accessToken = tokenProvider.createAccessToken(savedMember.getId(), savedMember.getNickname()); + inMemoryTokenPairRepository.add(refreshToken, accessToken); + authService = new AuthService(memberService, googleInfoProvider, tokenProvider, inMemoryTokenPairRepository); + } @AfterEach @@ -80,19 +93,16 @@ void success_login() { assertThat(result.getAccessToken()).isEqualTo(accessToken); assertThat(result.getRefreshToken()).isEqualTo(refreshToken); + assertDoesNotThrow(() -> inMemoryTokenPairRepository.validateTokenPair(refreshToken, accessToken)); } - @DisplayName("올바른 refresh 토큰이 들어오면 access 토큰을 재발급해준다.") + @DisplayName("올바른 refresh 토큰과 access 토큰이 들어오면 access 토큰을 재발급해준다.") @Test void success_reissue() { //given - final String refreshToken = tokenProvider.createRefreshToken( - savedMember.getId(), - savedMember.getNickname()); - //when final ReissueAccessTokenResponse result = authService.reissueAccessTokenByRefreshToken( - refreshToken); + refreshToken, accessToken); //then final String accessToken = tokenProvider.createAccessToken( @@ -111,13 +121,13 @@ void fail_reissue_invalid_refreshToken() { 100L, "asdzzxcwetg2adfvssd3xZcZXCZvzx"); - final String refreshToken = inValidTokenProvider.createRefreshToken( + final String wrongRefreshToken = inValidTokenProvider.createRefreshToken( savedMember.getId(), savedMember.getNickname()); //when //then - assertThatThrownBy(() -> authService.reissueAccessTokenByRefreshToken(refreshToken)) + assertThatThrownBy(() -> authService.reissueAccessTokenByRefreshToken(wrongRefreshToken, accessToken)) .isInstanceOf(TokenException.NotIssuedTokenException.class); } @@ -136,7 +146,7 @@ void fail_reissue_expired_refreshToken() { //when //then - assertThatThrownBy(() -> authService.reissueAccessTokenByRefreshToken(refreshToken)) + assertThatThrownBy(() -> authService.reissueAccessTokenByRefreshToken(refreshToken, accessToken)) .isInstanceOf(TokenException.ExpiredTokenException.class); } } diff --git a/backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java b/backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java new file mode 100644 index 000000000..3ccfa38a3 --- /dev/null +++ b/backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java @@ -0,0 +1,50 @@ +package shook.shook.auth.repository; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import shook.shook.auth.exception.TokenException.RefreshTokenNotFoundException; +import shook.shook.auth.exception.TokenException.TokenPairNotMatchingException; + +class InMemoryTokenPairRepositoryTest { + + @DisplayName("refreshToken과 accessToken이 올바른 쌍을 가지고 있으면 예외를 처리하지 않는다.") + @Test + void successValidateTokenPair() { + // given + final InMemoryTokenPairRepository inMemoryTokenPairRepository = new InMemoryTokenPairRepository(); + inMemoryTokenPairRepository.add("refreshToken", "accessToken"); + + // when + // then + assertDoesNotThrow(() -> inMemoryTokenPairRepository.validateTokenPair("refreshToken", "accessToken")); + } + + @DisplayName("존재하지 않는 refreshToken이면 예외를 발생한다.") + @Test + void failValidateTokenPair_refreshTokenNotExist() { + // given + final InMemoryTokenPairRepository inMemoryTokenPairRepository = new InMemoryTokenPairRepository(); + inMemoryTokenPairRepository.add("refreshToken", "accessToken"); + + // when + // then + assertThatThrownBy(() -> inMemoryTokenPairRepository.validateTokenPair("wrongRefreshToken", "accessToken")) + .isInstanceOf(RefreshTokenNotFoundException.class); + } + + @DisplayName("refreshToken에 해당하는 accessToken이 매칭되지 않으면 예외를 발생한다.") + @Test + void failValidateTokenPair_notMatching() { + // given + final InMemoryTokenPairRepository inMemoryTokenPairRepository = new InMemoryTokenPairRepository(); + inMemoryTokenPairRepository.add("refreshToken", "accessToken"); + + // when + // then + assertThatThrownBy(() -> inMemoryTokenPairRepository.validateTokenPair("refreshToken", "wrongAccessToken")) + .isInstanceOf(TokenPairNotMatchingException.class); + } +} diff --git a/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java b/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java index 0d3f3aaa1..5bee26b79 100644 --- a/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java +++ b/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java @@ -6,6 +6,7 @@ import io.restassured.RestAssured; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -36,11 +37,16 @@ class AccessTokenReissueControllerTest { @Autowired private TokenProvider tokenProvider; + private String refreshToken; + private String accessToken; + @BeforeEach void setUp() { RestAssured.port = port; dataCleaner.clear(); savedMember = memberRepository.save(new Member("shook@wooteco.com", "shook")); + refreshToken = tokenProvider.createRefreshToken(savedMember.getId(), savedMember.getNickname()); + accessToken = tokenProvider.createAccessToken(savedMember.getId(), savedMember.getNickname()); } @AfterEach @@ -48,18 +54,18 @@ void delete() { memberRepository.delete(savedMember); } + @Disabled @DisplayName("올바른 refreshToken을 통해 accessToken 재발급을 요청하면 accessToken과 상태코드 200을 반환한다.") @Test void success_reissue_accessToken() { //given - final String refreshToken = tokenProvider.createRefreshToken( - savedMember.getId(), - savedMember.getNickname()); + final String authorization = "Bearer " + accessToken; //when final ReissueAccessTokenResponse response = RestAssured.given().log().all() + .header("Authorization", authorization) .cookie("refreshToken", refreshToken) - .when().log().all().get("/reissue") + .when().log().all().post("/reissue") .then().statusCode(HttpStatus.OK.value()) .extract().body().as(ReissueAccessTokenResponse.class); @@ -76,7 +82,8 @@ void fail_reissue_accessToken() { //when //then RestAssured.given().log().all() - .when().log().all().get("/reissue") + .header("Authorization", "authorization") + .when().log().all().post("/reissue") .then().statusCode(HttpStatus.UNAUTHORIZED.value()); } } diff --git a/backend/src/test/java/shook/shook/exceptionhandler/ControllerAdviceTest.java b/backend/src/test/java/shook/shook/exceptionhandler/ControllerAdviceTest.java index cec234ba9..9960644a1 100644 --- a/backend/src/test/java/shook/shook/exceptionhandler/ControllerAdviceTest.java +++ b/backend/src/test/java/shook/shook/exceptionhandler/ControllerAdviceTest.java @@ -47,6 +47,8 @@ private static Stream exceptionTestData() { return Stream.of( new ExceptionTestData(new TokenException.NotIssuedTokenException(), 401), new ExceptionTestData(new TokenException.ExpiredTokenException(), 401), + new ExceptionTestData(new TokenException.TokenPairNotMatchingException(), 401), + new ExceptionTestData(new TokenException.RefreshTokenNotFoundException(), 401), new ExceptionTestData(new OAuthException.InvalidAuthorizationCodeException(), 503), new ExceptionTestData(new OAuthException.InvalidAccessTokenException(), 503), From f9f5d3d005d28c85d39243cb5df58b1a587e9be5 Mon Sep 17 00:00:00 2001 From: seokhwan-an Date: Tue, 19 Sep 2023 11:38:15 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20scheduler=EB=A5=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=B4=20InMemoryTokenPairRepository=EB=A5=BC=20=EA=B0=B1?= =?UTF-8?q?=EC=8B=A0=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/build.gradle | 1 + .../auth/application/TokenPairScheduler.java | 28 ++++++ .../InMemoryTokenPairRepository.java | 12 +++ .../src/main/resources/application-test.yml | 3 + backend/src/main/resources/application.yml | 4 + .../application/TokenPairSchedulerTest.java | 86 +++++++++++++++++++ 6 files changed, 134 insertions(+) create mode 100644 backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java create mode 100644 backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java diff --git a/backend/build.gradle b/backend/build.gradle index 3dbd51f0d..b4b83601a 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -43,6 +43,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' + testImplementation 'org.awaitility:awaitility:4.2.0' //log to slack implementation 'com.github.maricn:logback-slack-appender:1.4.0' diff --git a/backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java b/backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java new file mode 100644 index 000000000..a1d853896 --- /dev/null +++ b/backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java @@ -0,0 +1,28 @@ +package shook.shook.auth.application; + +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import shook.shook.auth.exception.TokenException; +import shook.shook.auth.repository.InMemoryTokenPairRepository; + +@RequiredArgsConstructor +@Component +public class TokenPairScheduler { + + private final TokenProvider tokenProvider; + private final InMemoryTokenPairRepository inMemoryTokenPairRepository; + + @Scheduled(cron = "${schedules.cron}") + public void renewInMemoryTokenPairRepository() { + final Set refreshTokens = inMemoryTokenPairRepository.getTokenPairs().keySet(); + refreshTokens.forEach(refreshToken -> { + try { + tokenProvider.parseClaims(refreshToken); + } catch (TokenException.ExpiredTokenException e) { + inMemoryTokenPairRepository.delete(refreshToken); + } + }); + } +} diff --git a/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java b/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java index f32c8bf09..7db127431 100644 --- a/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java +++ b/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java @@ -27,4 +27,16 @@ public void add(final String refreshToken, final String accessToken) { public void update(final String refreshToken, final String accessToken) { tokenPairs.put(refreshToken, accessToken); } + + public void delete(final String refreshToken) { + tokenPairs.remove(refreshToken); + } + + public Map getTokenPairs() { + return tokenPairs; + } + + public void clear() { + tokenPairs.clear(); + } } diff --git a/backend/src/main/resources/application-test.yml b/backend/src/main/resources/application-test.yml index 69422dbfa..e6399fb61 100644 --- a/backend/src/main/resources/application-test.yml +++ b/backend/src/main/resources/application-test.yml @@ -40,3 +40,6 @@ excel: video-url-delimiter: "=" killingpart-data-delimiter: " " song-length-suffix: "s" + +schedules: + cron: 0/1 * * * * * diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 4277ac4e3..a5f593e73 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -58,3 +58,7 @@ excel: video-url-delimiter: "v=" killingpart-data-delimiter: " " song-length-suffix: "초" + +# Properties Only For local +schedules: + cron: "0 0 0/1 * * *" diff --git a/backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java b/backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java new file mode 100644 index 000000000..7fc4bb0ef --- /dev/null +++ b/backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java @@ -0,0 +1,86 @@ +package shook.shook.auth.application; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.scheduling.annotation.EnableScheduling; +import shook.shook.auth.repository.InMemoryTokenPairRepository; + +@EnableScheduling +@SpringBootTest +class TokenPairSchedulerTest { + + @Autowired + private InMemoryTokenPairRepository inMemoryTokenPairRepository; + + private TokenProvider tokenProvider; + private TokenProvider expiredTokenProvider; + + @BeforeEach + void setting() { + tokenProvider = new TokenProvider(1200, 634000, "asdkfwofk23ksdfowsrk4sdkf"); + expiredTokenProvider = new TokenProvider(0, 0, "asdkfwofk23ksdfowsrk4sdkf"); + } + + @AfterEach + void clear() { + inMemoryTokenPairRepository.clear(); + } + + @DisplayName("tokenPairSechduler를 통해 inMemoryTokenPairRepository를 갱신한다.") + @Test + void renewInMemoryTokenPairRepository() { + // given + final String refreshToken = tokenProvider.createRefreshToken(1L, "shook"); + final String accessToken = tokenProvider.createAccessToken(1L, "shook"); + final String expiredRefreshToken = expiredTokenProvider.createRefreshToken(2L, "expiredShook"); + final String expiredAccessToken = expiredTokenProvider.createAccessToken(2L, "expiredShook"); + + inMemoryTokenPairRepository.add(refreshToken, accessToken); + inMemoryTokenPairRepository.add(expiredRefreshToken, expiredAccessToken); + + // when + final TokenPairScheduler tokenPairScheduler = new TokenPairScheduler(tokenProvider, inMemoryTokenPairRepository); + tokenPairScheduler.renewInMemoryTokenPairRepository(); + + // then + final Map tokenPairs = inMemoryTokenPairRepository.getTokenPairs(); + + assertThat(tokenPairs.size()).isOne(); + assertThat(tokenPairs.get(refreshToken)).isEqualTo(accessToken); + assertThat(tokenPairs.containsKey(expiredRefreshToken)).isFalse(); + } + + @Test + @DisplayName("1초마다 동작하는 scheduler로 inMemoryTokenPairRepository를 갱신한다.") + void renewInMemoryTokenPairRepositoryWithScheduler() { + // given + final String refreshToken = tokenProvider.createRefreshToken(1L, "shook"); + final String accessToken = tokenProvider.createAccessToken(1L, "shook"); + final String expiredRefreshToken = expiredTokenProvider.createRefreshToken(2L, "expiredShook"); + final String expiredAccessToken = expiredTokenProvider.createAccessToken(2L, "expiredShook"); + + inMemoryTokenPairRepository.add(refreshToken, accessToken); + inMemoryTokenPairRepository.add(expiredRefreshToken, expiredAccessToken); + + // when + final Map tokenPairs = inMemoryTokenPairRepository.getTokenPairs(); + // then + Awaitility.await() + .atMost(2, TimeUnit.SECONDS) + .untilAsserted(() -> { + assertThat(tokenPairs.size()).isOne(); + assertThat(tokenPairs.get(refreshToken)).isEqualTo(accessToken); + assertThat(tokenPairs.containsKey(expiredRefreshToken)).isFalse(); + }); + } +} + From 6d9071c5c6bdda350f9f3bbdaa8e55f6a621bec0 Mon Sep 17 00:00:00 2001 From: seokhwan-an Date: Tue, 19 Sep 2023 12:51:38 +0900 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=86=B5=EA=B3=BC=EB=90=98=EC=A7=80=20=EC=95=8A=EC=95=98?= =?UTF-8?q?=EB=8D=98=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/shook/shook/auth/application/AuthService.java | 5 +++++ .../auth/application/dto/ReissueAccessTokenResponse.java | 4 ++-- .../shook/shook/auth/ui/AccessTokenReissueController.java | 2 +- .../shook/shook/auth/ui/openapi/AccessTokenReissueApi.java | 4 ++-- .../shook/auth/ui/AccessTokenReissueControllerTest.java | 7 +++++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/shook/shook/auth/application/AuthService.java b/backend/src/main/java/shook/shook/auth/application/AuthService.java index 60afb42bb..f23f6eba7 100644 --- a/backend/src/main/java/shook/shook/auth/application/AuthService.java +++ b/backend/src/main/java/shook/shook/auth/application/AuthService.java @@ -1,6 +1,7 @@ package shook.shook.auth.application; import io.jsonwebtoken.Claims; +import java.util.Map; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import shook.shook.auth.application.dto.GoogleAccessTokenResponse; @@ -40,6 +41,10 @@ public TokenPair login(final String authorizationCode) { } public ReissueAccessTokenResponse reissueAccessTokenByRefreshToken(final String refreshToken, final String accessToken) { + final Map tokenPairs = inMemoryTokenPairRepository.getTokenPairs(); + for (String a : tokenPairs.keySet()) { + System.out.println(a.equals(refreshToken)); + } final Claims claims = tokenProvider.parseClaims(refreshToken); final Long memberId = claims.get("memberId", Long.class); final String nickname = claims.get("nickname", String.class); diff --git a/backend/src/main/java/shook/shook/auth/application/dto/ReissueAccessTokenResponse.java b/backend/src/main/java/shook/shook/auth/application/dto/ReissueAccessTokenResponse.java index 190bf91e7..5491355b6 100644 --- a/backend/src/main/java/shook/shook/auth/application/dto/ReissueAccessTokenResponse.java +++ b/backend/src/main/java/shook/shook/auth/application/dto/ReissueAccessTokenResponse.java @@ -4,11 +4,11 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.NoArgsConstructor; @Schema(description = "액세스 토큰 재발급 응답") @AllArgsConstructor -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PRIVATE) @Getter public class ReissueAccessTokenResponse { diff --git a/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java b/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java index 659c242e0..3f0bb8b8b 100644 --- a/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java +++ b/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java @@ -31,7 +31,7 @@ public ResponseEntity reissueAccessToken( } final String accessToken = authorization.split(TOKEN_PREFIX)[1]; final ReissueAccessTokenResponse response = - authService.reissueAccessTokenByRefreshToken(accessToken, refreshToken); + authService.reissueAccessTokenByRefreshToken(refreshToken, accessToken); return ResponseEntity.ok(response); } diff --git a/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java b/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java index 21f2c0375..eff76a302 100644 --- a/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java +++ b/backend/src/main/java/shook/shook/auth/ui/openapi/AccessTokenReissueApi.java @@ -6,7 +6,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import shook.shook.auth.application.dto.ReissueAccessTokenResponse; @@ -35,7 +35,7 @@ public interface AccessTokenReissueApi { ) } ) - @GetMapping("/reissue") + @PostMapping("/reissue") ResponseEntity reissueAccessToken( final String refreshToken, @RequestHeader("Authorization") final String authorization diff --git a/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java b/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java index 5bee26b79..2fc55dbaa 100644 --- a/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java +++ b/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java @@ -6,7 +6,6 @@ import io.restassured.RestAssured; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -16,6 +15,7 @@ import org.springframework.http.HttpStatus; import shook.shook.auth.application.TokenProvider; import shook.shook.auth.application.dto.ReissueAccessTokenResponse; +import shook.shook.auth.repository.InMemoryTokenPairRepository; import shook.shook.member.domain.Member; import shook.shook.member.domain.repository.MemberRepository; import shook.shook.support.DataCleaner; @@ -37,6 +37,9 @@ class AccessTokenReissueControllerTest { @Autowired private TokenProvider tokenProvider; + @Autowired + private InMemoryTokenPairRepository inMemoryTokenPairRepository; + private String refreshToken; private String accessToken; @@ -47,6 +50,7 @@ void setUp() { savedMember = memberRepository.save(new Member("shook@wooteco.com", "shook")); refreshToken = tokenProvider.createRefreshToken(savedMember.getId(), savedMember.getNickname()); accessToken = tokenProvider.createAccessToken(savedMember.getId(), savedMember.getNickname()); + inMemoryTokenPairRepository.add(refreshToken, accessToken); } @AfterEach @@ -54,7 +58,6 @@ void delete() { memberRepository.delete(savedMember); } - @Disabled @DisplayName("올바른 refreshToken을 통해 accessToken 재발급을 요청하면 accessToken과 상태코드 200을 반환한다.") @Test void success_reissue_accessToken() { From d83945ba9048a36e57722933b76f714a749367e9 Mon Sep 17 00:00:00 2001 From: seokhwan-an Date: Wed, 20 Sep 2023 15:46:37 +0900 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 세부사항 - InMemoryTokenPairRepository에서 add와 update를 하나의 메소드로 관리하기 - HttpHeaders 이용하기 - 코드 가독성 향상 시키기 --- .../shook/shook/auth/application/AuthService.java | 9 ++------- .../shook/auth/application/TokenPairScheduler.java | 6 +++--- .../auth/repository/InMemoryTokenPairRepository.java | 6 +----- .../shook/auth/ui/AccessTokenReissueController.java | 3 ++- .../shook/shook/auth/application/AuthServiceTest.java | 3 +-- .../auth/application/TokenPairSchedulerTest.java | 11 +++++------ .../repository/InMemoryTokenPairRepositoryTest.java | 6 +++--- .../auth/ui/AccessTokenReissueControllerTest.java | 2 +- 8 files changed, 18 insertions(+), 28 deletions(-) diff --git a/backend/src/main/java/shook/shook/auth/application/AuthService.java b/backend/src/main/java/shook/shook/auth/application/AuthService.java index f23f6eba7..39ffac45c 100644 --- a/backend/src/main/java/shook/shook/auth/application/AuthService.java +++ b/backend/src/main/java/shook/shook/auth/application/AuthService.java @@ -1,7 +1,6 @@ package shook.shook.auth.application; import io.jsonwebtoken.Claims; -import java.util.Map; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import shook.shook.auth.application.dto.GoogleAccessTokenResponse; @@ -36,22 +35,18 @@ public TokenPair login(final String authorizationCode) { final String nickname = member.getNickname(); final String accessToken = tokenProvider.createAccessToken(memberId, nickname); final String refreshToken = tokenProvider.createRefreshToken(memberId, nickname); - inMemoryTokenPairRepository.add(refreshToken, accessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(refreshToken, accessToken); return new TokenPair(accessToken, refreshToken); } public ReissueAccessTokenResponse reissueAccessTokenByRefreshToken(final String refreshToken, final String accessToken) { - final Map tokenPairs = inMemoryTokenPairRepository.getTokenPairs(); - for (String a : tokenPairs.keySet()) { - System.out.println(a.equals(refreshToken)); - } final Claims claims = tokenProvider.parseClaims(refreshToken); final Long memberId = claims.get("memberId", Long.class); final String nickname = claims.get("nickname", String.class); inMemoryTokenPairRepository.validateTokenPair(refreshToken, accessToken); final String reissuedAccessToken = tokenProvider.createAccessToken(memberId, nickname); - inMemoryTokenPairRepository.update(refreshToken, reissuedAccessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(refreshToken, reissuedAccessToken); return new ReissueAccessTokenResponse(reissuedAccessToken); } } diff --git a/backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java b/backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java index a1d853896..fb01ca738 100644 --- a/backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java +++ b/backend/src/main/java/shook/shook/auth/application/TokenPairScheduler.java @@ -15,14 +15,14 @@ public class TokenPairScheduler { private final InMemoryTokenPairRepository inMemoryTokenPairRepository; @Scheduled(cron = "${schedules.cron}") - public void renewInMemoryTokenPairRepository() { + public void removeExpiredTokenPair() { final Set refreshTokens = inMemoryTokenPairRepository.getTokenPairs().keySet(); - refreshTokens.forEach(refreshToken -> { + for (String refreshToken : refreshTokens) { try { tokenProvider.parseClaims(refreshToken); } catch (TokenException.ExpiredTokenException e) { inMemoryTokenPairRepository.delete(refreshToken); } - }); + } } } diff --git a/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java b/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java index 7db127431..0920e4b64 100644 --- a/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java +++ b/backend/src/main/java/shook/shook/auth/repository/InMemoryTokenPairRepository.java @@ -20,11 +20,7 @@ public void validateTokenPair(final String refreshToken, final String accessToke } } - public void add(final String refreshToken, final String accessToken) { - tokenPairs.put(refreshToken, accessToken); - } - - public void update(final String refreshToken, final String accessToken) { + public void addOrUpdateTokenPair(final String refreshToken, final String accessToken) { tokenPairs.put(refreshToken, accessToken); } diff --git a/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java b/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java index 3f0bb8b8b..16eacf444 100644 --- a/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java +++ b/backend/src/main/java/shook/shook/auth/ui/AccessTokenReissueController.java @@ -1,6 +1,7 @@ package shook.shook.auth.ui; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.PostMapping; @@ -24,7 +25,7 @@ public class AccessTokenReissueController implements AccessTokenReissueApi { @PostMapping("/reissue") public ResponseEntity reissueAccessToken( @CookieValue(value = REFRESH_TOKEN_KEY, defaultValue = EMPTY_REFRESH_TOKEN) final String refreshToken, - @RequestHeader("Authorization") final String authorization + @RequestHeader(HttpHeaders.AUTHORIZATION) final String authorization ) { if (refreshToken.equals(EMPTY_REFRESH_TOKEN)) { throw new AuthorizationException.RefreshTokenNotFoundException(); diff --git a/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java b/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java index c1666eeb2..ecc31b79a 100644 --- a/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java +++ b/backend/src/test/java/shook/shook/auth/application/AuthServiceTest.java @@ -57,9 +57,8 @@ void setUp() { savedMember = memberRepository.save(new Member("shook@wooteco.com", "shook")); refreshToken = tokenProvider.createRefreshToken(savedMember.getId(), savedMember.getNickname()); accessToken = tokenProvider.createAccessToken(savedMember.getId(), savedMember.getNickname()); - inMemoryTokenPairRepository.add(refreshToken, accessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(refreshToken, accessToken); authService = new AuthService(memberService, googleInfoProvider, tokenProvider, inMemoryTokenPairRepository); - } @AfterEach diff --git a/backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java b/backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java index 7fc4bb0ef..05aa20c2c 100644 --- a/backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java +++ b/backend/src/test/java/shook/shook/auth/application/TokenPairSchedulerTest.java @@ -44,12 +44,12 @@ void renewInMemoryTokenPairRepository() { final String expiredRefreshToken = expiredTokenProvider.createRefreshToken(2L, "expiredShook"); final String expiredAccessToken = expiredTokenProvider.createAccessToken(2L, "expiredShook"); - inMemoryTokenPairRepository.add(refreshToken, accessToken); - inMemoryTokenPairRepository.add(expiredRefreshToken, expiredAccessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(refreshToken, accessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(expiredRefreshToken, expiredAccessToken); // when final TokenPairScheduler tokenPairScheduler = new TokenPairScheduler(tokenProvider, inMemoryTokenPairRepository); - tokenPairScheduler.renewInMemoryTokenPairRepository(); + tokenPairScheduler.removeExpiredTokenPair(); // then final Map tokenPairs = inMemoryTokenPairRepository.getTokenPairs(); @@ -68,8 +68,8 @@ void renewInMemoryTokenPairRepositoryWithScheduler() { final String expiredRefreshToken = expiredTokenProvider.createRefreshToken(2L, "expiredShook"); final String expiredAccessToken = expiredTokenProvider.createAccessToken(2L, "expiredShook"); - inMemoryTokenPairRepository.add(refreshToken, accessToken); - inMemoryTokenPairRepository.add(expiredRefreshToken, expiredAccessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(refreshToken, accessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(expiredRefreshToken, expiredAccessToken); // when final Map tokenPairs = inMemoryTokenPairRepository.getTokenPairs(); @@ -83,4 +83,3 @@ void renewInMemoryTokenPairRepositoryWithScheduler() { }); } } - diff --git a/backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java b/backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java index 3ccfa38a3..12e864735 100644 --- a/backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java +++ b/backend/src/test/java/shook/shook/auth/repository/InMemoryTokenPairRepositoryTest.java @@ -15,7 +15,7 @@ class InMemoryTokenPairRepositoryTest { void successValidateTokenPair() { // given final InMemoryTokenPairRepository inMemoryTokenPairRepository = new InMemoryTokenPairRepository(); - inMemoryTokenPairRepository.add("refreshToken", "accessToken"); + inMemoryTokenPairRepository.addOrUpdateTokenPair("refreshToken", "accessToken"); // when // then @@ -27,7 +27,7 @@ void successValidateTokenPair() { void failValidateTokenPair_refreshTokenNotExist() { // given final InMemoryTokenPairRepository inMemoryTokenPairRepository = new InMemoryTokenPairRepository(); - inMemoryTokenPairRepository.add("refreshToken", "accessToken"); + inMemoryTokenPairRepository.addOrUpdateTokenPair("refreshToken", "accessToken"); // when // then @@ -40,7 +40,7 @@ void failValidateTokenPair_refreshTokenNotExist() { void failValidateTokenPair_notMatching() { // given final InMemoryTokenPairRepository inMemoryTokenPairRepository = new InMemoryTokenPairRepository(); - inMemoryTokenPairRepository.add("refreshToken", "accessToken"); + inMemoryTokenPairRepository.addOrUpdateTokenPair("refreshToken", "accessToken"); // when // then diff --git a/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java b/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java index 2fc55dbaa..36677e163 100644 --- a/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java +++ b/backend/src/test/java/shook/shook/auth/ui/AccessTokenReissueControllerTest.java @@ -50,7 +50,7 @@ void setUp() { savedMember = memberRepository.save(new Member("shook@wooteco.com", "shook")); refreshToken = tokenProvider.createRefreshToken(savedMember.getId(), savedMember.getNickname()); accessToken = tokenProvider.createAccessToken(savedMember.getId(), savedMember.getNickname()); - inMemoryTokenPairRepository.add(refreshToken, accessToken); + inMemoryTokenPairRepository.addOrUpdateTokenPair(refreshToken, accessToken); } @AfterEach From 4d5282cdc3951b19578d79d79b4ba8558b57c9e5 Mon Sep 17 00:00:00 2001 From: seokhwan-an Date: Wed, 20 Sep 2023 15:49:57 +0900 Subject: [PATCH 5/5] =?UTF-8?q?refactor:=20=EC=84=9C=EB=B8=8C=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=B5=9C=EC=8B=A0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/resources/shook-security | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/resources/shook-security b/backend/src/main/resources/shook-security index 30d5e0dbe..df2277d8f 160000 --- a/backend/src/main/resources/shook-security +++ b/backend/src/main/resources/shook-security @@ -1 +1 @@ -Subproject commit 30d5e0dbed67a9255a4d2674648c4f1cba526ebf +Subproject commit df2277d8f06fecff4e9836a14adccb908149c76a