From c08989962b0ea6e64f3e7c1cf2787b10bca5498c Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 01:58:43 +0900 Subject: [PATCH 01/17] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=94=84=EB=A7=81?= =?UTF-8?q?=20=EB=B9=88=EC=9C=BC=EB=A1=9C=20=ED=99=9C=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4=20private=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/solidconnection/util/JwtUtils.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/example/solidconnection/util/JwtUtils.java b/src/main/java/com/example/solidconnection/util/JwtUtils.java index 040beb9ba..9d4857a8b 100644 --- a/src/main/java/com/example/solidconnection/util/JwtUtils.java +++ b/src/main/java/com/example/solidconnection/util/JwtUtils.java @@ -15,9 +15,6 @@ public class JwtUtils { private static final String TOKEN_HEADER = "Authorization"; private static final String TOKEN_PREFIX = "Bearer "; - private JwtUtils() { - } - public static String parseTokenFromRequest(HttpServletRequest request) { String token = request.getHeader(TOKEN_HEADER); if (token == null || token.isBlank() || !token.startsWith(TOKEN_PREFIX)) { @@ -33,6 +30,7 @@ public static String parseSubject(String token, String secretKey) { throw new CustomException(INVALID_TOKEN); } } + public static Claims parseClaims(String token, String secretKey) throws ExpiredJwtException { return Jwts.parser() .setSigningKey(secretKey) From 89008fa81e2b9a81ce8f3012f53c45f9c5e034ab Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 02:11:46 +0900 Subject: [PATCH 02/17] =?UTF-8?q?refactor:=20=ED=97=A4=EB=8D=94=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=86=A0=ED=81=B0=20=EC=B6=94=EC=B6=9C=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=BD=94=EB=93=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 추가로, null 이 아니라 Optional 을 반환하여 빈 값 처리를 강제하도록 수정 --- .../filter/AuthorizationHeaderParser.java | 29 ++++++++++ .../filter/JwtAuthenticationFilter.java | 10 ++-- .../security/filter/SignOutCheckFilter.java | 7 +-- .../solidconnection/util/JwtUtils.java | 12 ----- .../filter/AuthorizationHeaderParserTest.java | 54 +++++++++++++++++++ .../solidconnection/util/JwtUtilsTest.java | 38 ------------- 6 files changed, 92 insertions(+), 58 deletions(-) create mode 100644 src/main/java/com/example/solidconnection/security/filter/AuthorizationHeaderParser.java create mode 100644 src/test/java/com/example/solidconnection/security/filter/AuthorizationHeaderParserTest.java diff --git a/src/main/java/com/example/solidconnection/security/filter/AuthorizationHeaderParser.java b/src/main/java/com/example/solidconnection/security/filter/AuthorizationHeaderParser.java new file mode 100644 index 000000000..8bbbc30e4 --- /dev/null +++ b/src/main/java/com/example/solidconnection/security/filter/AuthorizationHeaderParser.java @@ -0,0 +1,29 @@ +package com.example.solidconnection.security.filter; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class AuthorizationHeaderParser { + + private static final String TOKEN_HEADER = "Authorization"; + private static final String TOKEN_PREFIX = "Bearer "; + private static final int TOKEN_PREFIX_LENGTH = TOKEN_PREFIX.length(); + + public Optional parseToken(HttpServletRequest request) { + String token = request.getHeader(TOKEN_HEADER); + if (isInvalidFormat(token)) { + return Optional.empty(); + } + return Optional.of(token.substring(TOKEN_PREFIX_LENGTH)); + } + + private boolean isInvalidFormat(String token) { + return token == null || + token.isBlank() || + !token.startsWith(TOKEN_PREFIX) || + token.substring(TOKEN_PREFIX_LENGTH).isBlank(); + } +} diff --git a/src/main/java/com/example/solidconnection/security/filter/JwtAuthenticationFilter.java b/src/main/java/com/example/solidconnection/security/filter/JwtAuthenticationFilter.java index 39917d42e..8ee6a98e4 100644 --- a/src/main/java/com/example/solidconnection/security/filter/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/solidconnection/security/filter/JwtAuthenticationFilter.java @@ -15,8 +15,7 @@ import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; - -import static com.example.solidconnection.util.JwtUtils.parseTokenFromRequest; +import java.util.Optional; @Component @@ -24,18 +23,19 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final AuthenticationManager authenticationManager; + private final AuthorizationHeaderParser authorizationHeaderParser; @Override public void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException { - String token = parseTokenFromRequest(request); - if (token == null) { + Optional token = authorizationHeaderParser.parseToken(request); + if (token.isEmpty()) { filterChain.doFilter(request, response); return; } - JwtAuthentication authToken = createAuthentication(token); + JwtAuthentication authToken = createAuthentication(token.get()); Authentication auth = authenticationManager.authenticate(authToken); SecurityContextHolder.getContext().setAuthentication(auth); diff --git a/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java b/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java index 5c51c53cd..950e41c07 100644 --- a/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java +++ b/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java @@ -12,22 +12,23 @@ import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.util.Optional; import static com.example.solidconnection.common.exception.ErrorCode.USER_ALREADY_SIGN_OUT; -import static com.example.solidconnection.util.JwtUtils.parseTokenFromRequest; @Component @RequiredArgsConstructor public class SignOutCheckFilter extends OncePerRequestFilter { + private final AuthorizationHeaderParser authorizationHeaderParser; private final BlacklistChecker tokenBlacklistChecker; @Override protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException { - String token = parseTokenFromRequest(request); - if (token != null && hasSignedOut(token)) { + Optional token = authorizationHeaderParser.parseToken(request); + if (token.isPresent() && hasSignedOut(token.get())) { throw new CustomException(USER_ALREADY_SIGN_OUT); } filterChain.doFilter(request, response); diff --git a/src/main/java/com/example/solidconnection/util/JwtUtils.java b/src/main/java/com/example/solidconnection/util/JwtUtils.java index 9d4857a8b..fe2165cfd 100644 --- a/src/main/java/com/example/solidconnection/util/JwtUtils.java +++ b/src/main/java/com/example/solidconnection/util/JwtUtils.java @@ -4,7 +4,6 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; -import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; import static com.example.solidconnection.common.exception.ErrorCode.INVALID_TOKEN; @@ -12,17 +11,6 @@ @Component public class JwtUtils { - private static final String TOKEN_HEADER = "Authorization"; - private static final String TOKEN_PREFIX = "Bearer "; - - public static String parseTokenFromRequest(HttpServletRequest request) { - String token = request.getHeader(TOKEN_HEADER); - if (token == null || token.isBlank() || !token.startsWith(TOKEN_PREFIX)) { - return null; - } - return token.substring(TOKEN_PREFIX.length()); - } - public static String parseSubject(String token, String secretKey) { try { return parseClaims(token, secretKey).getSubject(); diff --git a/src/test/java/com/example/solidconnection/security/filter/AuthorizationHeaderParserTest.java b/src/test/java/com/example/solidconnection/security/filter/AuthorizationHeaderParserTest.java new file mode 100644 index 000000000..1d4ba2533 --- /dev/null +++ b/src/test/java/com/example/solidconnection/security/filter/AuthorizationHeaderParserTest.java @@ -0,0 +1,54 @@ +package com.example.solidconnection.security.filter; + +import com.example.solidconnection.support.TestContainerSpringBootTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +@TestContainerSpringBootTest +class AuthorizationHeaderParserTest { + + @Autowired + private AuthorizationHeaderParser authorizationHeaderParser; + + @Nested + class 요청으로부터_토큰을_추출한다 { + + @Test + void 지정한_형식의_토큰이_있으면_토큰을_반환한다() { + // given + MockHttpServletRequest request = new MockHttpServletRequest(); + String token = "token"; + request.addHeader("Authorization", "Bearer " + token); + + // when + Optional extractedToken = authorizationHeaderParser.parseToken(request); + + // then + assertThat(extractedToken).get().isEqualTo(token); + } + + @Test + void 형식에_맞는_토큰이_없으면_빈_값을_반환한다() { + // given + MockHttpServletRequest noHeader = new MockHttpServletRequest(); + MockHttpServletRequest wrongPrefix = new MockHttpServletRequest(); + wrongPrefix.addHeader("Authorization", "Wrong token"); + MockHttpServletRequest emptyToken = new MockHttpServletRequest(); + emptyToken.addHeader("Authorization", "Bearer "); + + // when & then + assertAll( + () -> assertThat(authorizationHeaderParser.parseToken(noHeader)).isEmpty(), + () -> assertThat(authorizationHeaderParser.parseToken(wrongPrefix)).isEmpty(), + () -> assertThat(authorizationHeaderParser.parseToken(emptyToken)).isEmpty() + ); + } + } +} diff --git a/src/test/java/com/example/solidconnection/util/JwtUtilsTest.java b/src/test/java/com/example/solidconnection/util/JwtUtilsTest.java index c57e85193..28116322f 100644 --- a/src/test/java/com/example/solidconnection/util/JwtUtilsTest.java +++ b/src/test/java/com/example/solidconnection/util/JwtUtilsTest.java @@ -7,56 +7,18 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.springframework.mock.web.MockHttpServletRequest; import java.util.Date; import static com.example.solidconnection.util.JwtUtils.parseSubject; -import static com.example.solidconnection.util.JwtUtils.parseTokenFromRequest; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; -import static org.junit.jupiter.api.Assertions.assertAll; @DisplayName("JwtUtils 테스트") class JwtUtilsTest { private final String jwtSecretKey = "jwt-secret-key"; - @Nested - class 요청으로부터_토큰을_추출한다 { - - @Test - void 토큰이_있으면_토큰을_반환한다() { - // given - MockHttpServletRequest request = new MockHttpServletRequest(); - String token = "token"; - request.addHeader("Authorization", "Bearer " + token); - - // when - String extractedToken = parseTokenFromRequest(request); - - // then - assertThat(extractedToken).isEqualTo(token); - } - - @Test - void 토큰이_없으면_null_을_반환한다() { - // given - MockHttpServletRequest noHeader = new MockHttpServletRequest(); - MockHttpServletRequest wrongPrefix = new MockHttpServletRequest(); - wrongPrefix.addHeader("Authorization", "Wrong token"); - MockHttpServletRequest emptyToken = new MockHttpServletRequest(); - wrongPrefix.addHeader("Authorization", "Bearer "); - - // when & then - assertAll( - () -> assertThat(parseTokenFromRequest(noHeader)).isNull(), - () -> assertThat(parseTokenFromRequest(wrongPrefix)).isNull(), - () -> assertThat(parseTokenFromRequest(emptyToken)).isNull() - ); - } - } - @Nested class 토큰으로부터_subject_를_추출한다 { From 8526aabe9a78b1f83d0bad2732791b1cd9489f97 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 02:14:11 +0900 Subject: [PATCH 03/17] =?UTF-8?q?refactor:=20=ED=86=A0=ED=81=B0=EC=9D=98?= =?UTF-8?q?=20=EB=B8=94=EB=9E=99=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/AuthService.java | 3 +- .../auth/service/AuthTokenProvider.java | 18 +----- .../auth/service/TokenBlackListService.java | 32 +++++++++++ .../security/filter/SignOutCheckFilter.java | 4 +- .../auth/service/AuthServiceTest.java | 7 ++- .../auth/service/AuthTokenProviderTest.java | 38 ------------- .../service/TokenBlackListServiceTest.java | 57 +++++++++++++++++++ 7 files changed, 99 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java create mode 100644 src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java diff --git a/src/main/java/com/example/solidconnection/auth/service/AuthService.java b/src/main/java/com/example/solidconnection/auth/service/AuthService.java index 496e48724..2189960d8 100644 --- a/src/main/java/com/example/solidconnection/auth/service/AuthService.java +++ b/src/main/java/com/example/solidconnection/auth/service/AuthService.java @@ -17,6 +17,7 @@ public class AuthService { private final AuthTokenProvider authTokenProvider; + private final TokenBlackListService tokenBlackListService; /* * 로그아웃한다. @@ -26,7 +27,7 @@ public class AuthService { public void signOut(String token) { AccessToken accessToken = authTokenProvider.toAccessToken(token); authTokenProvider.deleteRefreshTokenByAccessToken(accessToken); - authTokenProvider.addToBlacklist(accessToken); + tokenBlackListService.addToBlacklist(accessToken); } /* diff --git a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java index fa2a064cc..f86dd0ce7 100644 --- a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java @@ -10,7 +10,7 @@ import java.util.Objects; @Component -public class AuthTokenProvider extends TokenProvider implements BlacklistChecker { +public class AuthTokenProvider extends TokenProvider { public AuthTokenProvider(JwtProperties jwtProperties, RedisTemplate redisTemplate) { super(jwtProperties, redisTemplate); @@ -27,16 +27,6 @@ public RefreshToken generateAndSaveRefreshToken(Subject subject) { return new RefreshToken(subject, token); } - /* - * 액세스 토큰을 블랙리스트에 저장한다. - * - key = BLACKLIST:{accessToken} - * - value = "signOut" -> key 의 존재만 확인하므로, value 에는 무슨 값이 들어가도 상관없다. - * */ - public void addToBlacklist(AccessToken accessToken) { - String blackListKey = TokenType.BLACKLIST.addPrefix(accessToken.token()); - redisTemplate.opsForValue().set(blackListKey, "signOut"); - } - /* * 유효한 리프레시 토큰인지 확인한다. * - 요청된 토큰과 같은 subject 의 리프레시 토큰을 조회한다. @@ -55,12 +45,6 @@ public void deleteRefreshTokenByAccessToken(AccessToken accessToken) { redisTemplate.delete(refreshTokenKey); } - @Override - public boolean isTokenBlacklisted(String accessToken) { - String blackListTokenKey = TokenType.BLACKLIST.addPrefix(accessToken); - return redisTemplate.hasKey(blackListTokenKey); - } - public Subject parseSubject(String token) { String subject = JwtUtils.parseSubject(token, jwtProperties.secret()); return new Subject(subject); diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java b/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java new file mode 100644 index 000000000..39612c85b --- /dev/null +++ b/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java @@ -0,0 +1,32 @@ +package com.example.solidconnection.auth.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import static com.example.solidconnection.auth.domain.TokenType.BLACKLIST; + +@Component +@RequiredArgsConstructor +public class TokenBlackListService implements BlacklistChecker { + + private static final String SIGN_OUT_VALUE = "signOut"; + + private final RedisTemplate redisTemplate; + + /* + * 액세스 토큰을 블랙리스트에 저장한다. + * - key = BLACKLIST:{accessToken} + * - value = {SIGN_OUT_VALUE} -> key 의 존재만 확인하므로, value 에는 무슨 값이 들어가도 상관없다. + * */ + public void addToBlacklist(AccessToken accessToken) { + String blackListKey = BLACKLIST.addPrefix(accessToken.token()); + redisTemplate.opsForValue().set(blackListKey, SIGN_OUT_VALUE); + } + + @Override + public boolean isTokenBlacklisted(String accessToken) { + String blackListTokenKey = BLACKLIST.addPrefix(accessToken); + return redisTemplate.hasKey(blackListTokenKey); + } +} diff --git a/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java b/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java index 950e41c07..afe1294bd 100644 --- a/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java +++ b/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java @@ -21,7 +21,7 @@ public class SignOutCheckFilter extends OncePerRequestFilter { private final AuthorizationHeaderParser authorizationHeaderParser; - private final BlacklistChecker tokenBlacklistChecker; + private final BlacklistChecker blacklistChecker; @Override protected void doFilterInternal(@NonNull HttpServletRequest request, @@ -35,6 +35,6 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, } private boolean hasSignedOut(String accessToken) { - return tokenBlacklistChecker.isTokenBlacklisted(accessToken); + return blacklistChecker.isTokenBlacklisted(accessToken); } } diff --git a/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java index 8fd57eae6..acf969540 100644 --- a/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java @@ -30,6 +30,9 @@ class AuthServiceTest { @Autowired private AuthTokenProvider authTokenProvider; + @Autowired + private TokenBlackListService tokenBlackListService; + @Autowired private RedisTemplate redisTemplate; @@ -49,7 +52,7 @@ class AuthServiceTest { String refreshTokenKey = TokenType.REFRESH.addPrefix(subject.value()); assertAll( () -> assertThat(redisTemplate.opsForValue().get(refreshTokenKey)).isNull(), - () -> assertThat(authTokenProvider.isTokenBlacklisted(accessToken.token())).isTrue() + () -> assertThat(tokenBlackListService.isTokenBlacklisted(accessToken.token())).isTrue() ); } @@ -69,7 +72,7 @@ class AuthServiceTest { assertAll( () -> assertThat(user.getQuitedAt()).isEqualTo(tomorrow), () -> assertThat(redisTemplate.opsForValue().get(refreshTokenKey)).isNull(), - () -> assertThat(authTokenProvider.isTokenBlacklisted(accessToken.token())).isTrue() + () -> assertThat(tokenBlackListService.isTokenBlacklisted(accessToken.token())).isTrue() ); } diff --git a/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java index dc35ab3a7..f13f24616 100644 --- a/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java @@ -85,44 +85,6 @@ class 리프레시_토큰을_제공한다 { } } - @Nested - class 블랙리스트를_관리한다 { - - @Test - void 액세스_토큰을_블랙리스트에_추가한다() { - // given - AccessToken accessToken = authTokenProvider.generateAccessToken(subject); // todo: issue#296 - - // when - authTokenProvider.addToBlacklist(accessToken); - - // then - String blackListTokenKey = TokenType.BLACKLIST.addPrefix(accessToken.token()); - String foundBlackListToken = redisTemplate.opsForValue().get(blackListTokenKey); - assertThat(foundBlackListToken).isNotNull(); - } - - /* - * todo: JwtUtils 나 TokenProvider 를 스프링 빈으로 주입받도록 변경한다. (issue#296) - * - 아래 테스트 코드에서는, 내부적으로 JwtUtils.parseSubject() 메서드가 호출될 때 발생하는 예외를 피하기 위해 jwt토큰을 생성한다. - * - 테스트 작성자는 예외 발생을 피하기 위해 "제대로된 jwt 토큰 생성이 필요하다"는 것을 몰라야한다. - * - 따라서, JwtUtils 나 TokenProvider 를 스프링 빈으로 주입받도록 변경하고, 테스트에서 mock 을 사용하여 의존성을 끊을 필요가 있다. - */ - @Test - void 블랙리스트에_있는_토큰인지_확인한다() { - // given - AccessToken accessToken = authTokenProvider.generateAccessToken(subject); - authTokenProvider.addToBlacklist(accessToken); - AccessToken notRegisteredAccessToken = authTokenProvider.generateAccessToken(new Subject("!")); - - // when, then - assertAll( - () -> assertThat(authTokenProvider.isTokenBlacklisted(accessToken.token())).isTrue(), - () -> assertThat(authTokenProvider.isTokenBlacklisted(notRegisteredAccessToken.token())).isFalse() - ); - } - } - @Test void 토큰으로부터_Subject_를_추출한다() { // given diff --git a/src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java new file mode 100644 index 000000000..ffe823df8 --- /dev/null +++ b/src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java @@ -0,0 +1,57 @@ +package com.example.solidconnection.auth.service; + +import com.example.solidconnection.support.TestContainerSpringBootTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; + +import static com.example.solidconnection.auth.domain.TokenType.BLACKLIST; +import static org.assertj.core.api.Assertions.assertThat; + +@TestContainerSpringBootTest +class TokenBlackListServiceTest { + + @Autowired + private TokenBlackListService tokenBlackListService; + + @Autowired + private RedisTemplate redisTemplate; + + @Test + void 액세스_토큰을_블랙리스트에_추가한다() { + // given + AccessToken accessToken = new AccessToken("subject", "token"); + + // when + tokenBlackListService.addToBlacklist(accessToken); + + // then + String blackListTokenKey = BLACKLIST.addPrefix(accessToken.token()); + String foundBlackListToken = redisTemplate.opsForValue().get(blackListTokenKey); + assertThat(foundBlackListToken).isNotNull(); + } + + @Nested + class 블랙리스트에_있는_토큰인지_확인한다 { + + @Test + void 블랙리스트에_토큰이_있는_경우() { + // given + AccessToken accessToken = new AccessToken("subject", "token"); + tokenBlackListService.addToBlacklist(accessToken); + + // when, then + assertThat(tokenBlackListService.isTokenBlacklisted(accessToken.token())).isTrue(); + } + + @Test + void 블랙리스트에_토큰이_없는_경우() { + // given + AccessToken accessToken = new AccessToken("subject", "token"); + + // when, then + assertThat(tokenBlackListService.isTokenBlacklisted(accessToken.token())).isFalse(); + } + } +} From 4b912a62421e64bff6ce2682090db95ca5b667cc Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 02:38:11 +0900 Subject: [PATCH 04/17] =?UTF-8?q?refactor:=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=A0=9C=EA=B3=B5=EA=B3=BC=20=EA=B4=80=EB=A0=A8=EB=90=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20TokenProvider=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - JwtUtils를 사용하던 곳에서 TokenProvider를 주입받아 사용하게 하기 위한 사전 작업 --- .../auth/service/TokenProvider.java | 19 ++++++++++++- .../solidconnection/util/JwtUtils.java | 28 ------------------- 2 files changed, 18 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/com/example/solidconnection/util/JwtUtils.java diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java index 0f3552db2..1557c6100 100644 --- a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java @@ -1,8 +1,10 @@ package com.example.solidconnection.auth.service; import com.example.solidconnection.auth.domain.TokenType; +import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.security.config.JwtProperties; import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.data.redis.core.RedisTemplate; @@ -10,7 +12,7 @@ import java.util.Date; import java.util.concurrent.TimeUnit; -import static com.example.solidconnection.util.JwtUtils.parseSubject; +import static com.example.solidconnection.common.exception.ErrorCode.INVALID_TOKEN; public abstract class TokenProvider { @@ -44,4 +46,19 @@ protected final String saveToken(String token, TokenType tokenType) { ); return token; } + + public String parseSubject(String token, String secretKey) { + try { + return parseClaims(token, secretKey).getSubject(); + } catch (Exception e) { + throw new CustomException(INVALID_TOKEN); + } + } + + public Claims parseClaims(String token, String secretKey) throws ExpiredJwtException { + return Jwts.parser() + .setSigningKey(secretKey) + .parseClaimsJws(token) + .getBody(); + } } diff --git a/src/main/java/com/example/solidconnection/util/JwtUtils.java b/src/main/java/com/example/solidconnection/util/JwtUtils.java deleted file mode 100644 index fe2165cfd..000000000 --- a/src/main/java/com/example/solidconnection/util/JwtUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.example.solidconnection.util; - -import com.example.solidconnection.common.exception.CustomException; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ExpiredJwtException; -import io.jsonwebtoken.Jwts; -import org.springframework.stereotype.Component; - -import static com.example.solidconnection.common.exception.ErrorCode.INVALID_TOKEN; - -@Component -public class JwtUtils { - - public static String parseSubject(String token, String secretKey) { - try { - return parseClaims(token, secretKey).getSubject(); - } catch (Exception e) { - throw new CustomException(INVALID_TOKEN); - } - } - - public static Claims parseClaims(String token, String secretKey) throws ExpiredJwtException { - return Jwts.parser() - .setSigningKey(secretKey) - .parseClaimsJws(token) - .getBody(); - } -} From 0e44f1dc76b41fa2040358e54094881d0a415133 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 02:52:50 +0900 Subject: [PATCH 05/17] =?UTF-8?q?refactor:=20TokenProvider=EB=A5=BC=20abst?= =?UTF-8?q?ract=20=ED=81=B4=EB=9E=98=EC=8A=A4=EA=B0=80=20=EC=95=84?= =?UTF-8?q?=EB=8B=88=EB=9D=BC=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/TokenProvider.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java index 1557c6100..553480687 100644 --- a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java @@ -7,24 +7,23 @@ import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; import java.util.Date; import java.util.concurrent.TimeUnit; import static com.example.solidconnection.common.exception.ErrorCode.INVALID_TOKEN; -public abstract class TokenProvider { +@Component +@RequiredArgsConstructor +public class TokenProvider { - protected final JwtProperties jwtProperties; - protected final RedisTemplate redisTemplate; + private final JwtProperties jwtProperties; + private final RedisTemplate redisTemplate; - public TokenProvider(JwtProperties jwtProperties, RedisTemplate redisTemplate) { - this.jwtProperties = jwtProperties; - this.redisTemplate = redisTemplate; - } - - protected final String generateToken(String string, TokenType tokenType) { + public final String generateToken(String string, TokenType tokenType) { Claims claims = Jwts.claims().setSubject(string); Date now = new Date(); Date expiredDate = new Date(now.getTime() + tokenType.getExpireTime()); @@ -36,7 +35,7 @@ protected final String generateToken(String string, TokenType tokenType) { .compact(); } - protected final String saveToken(String token, TokenType tokenType) { + public final String saveToken(String token, TokenType tokenType) { String subject = parseSubject(token, jwtProperties.secret()); redisTemplate.opsForValue().set( tokenType.addPrefix(subject), From 0df626f8d9d2d2f081dc82ce9003c37853f434b3 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 02:53:39 +0900 Subject: [PATCH 06/17] =?UTF-8?q?refactor:=20TokenProvider=EB=A5=BC=20?= =?UTF-8?q?=EC=83=81=EC=86=8D=ED=95=98=EC=97=AC=20=EC=93=B0=EB=8D=98=20?= =?UTF-8?q?=EA=B3=B3=EC=97=90=EC=84=9C=20=EC=A3=BC=EC=9E=85=EB=B0=9B?= =?UTF-8?q?=EC=95=84=20=EC=93=B0=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/AuthTokenProvider.java | 21 +++++++++-------- .../service/EmailSignUpTokenProvider.java | 23 ++++++++----------- .../oauth/OAuthSignUpTokenProvider.java | 20 ++++++++-------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java index f86dd0ce7..19a64a5e1 100644 --- a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java @@ -3,27 +3,28 @@ import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.security.config.JwtProperties; import com.example.solidconnection.siteuser.domain.SiteUser; -import com.example.solidconnection.util.JwtUtils; +import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.Objects; @Component -public class AuthTokenProvider extends TokenProvider { +@RequiredArgsConstructor +public class AuthTokenProvider { - public AuthTokenProvider(JwtProperties jwtProperties, RedisTemplate redisTemplate) { - super(jwtProperties, redisTemplate); - } + private final JwtProperties jwtProperties; + private final RedisTemplate redisTemplate; + private final TokenProvider tokenProvider; public AccessToken generateAccessToken(Subject subject) { - String token = generateToken(subject.value(), TokenType.ACCESS); + String token = tokenProvider.generateToken(subject.value(), TokenType.ACCESS); return new AccessToken(subject, token); } public RefreshToken generateAndSaveRefreshToken(Subject subject) { - String token = generateToken(subject.value(), TokenType.REFRESH); - saveToken(token, TokenType.REFRESH); + String token = tokenProvider.generateToken(subject.value(), TokenType.REFRESH); + tokenProvider.saveToken(token, TokenType.REFRESH); return new RefreshToken(subject, token); } @@ -33,7 +34,7 @@ public RefreshToken generateAndSaveRefreshToken(Subject subject) { * - 조회된 리프레시 토큰과 요청된 토큰이 같은지 비교한다. * */ public boolean isValidRefreshToken(String requestedRefreshToken) { - String subject = JwtUtils.parseSubject(requestedRefreshToken, jwtProperties.secret()); + String subject = tokenProvider.parseSubject(requestedRefreshToken, jwtProperties.secret()); String refreshTokenKey = TokenType.REFRESH.addPrefix(subject); String foundRefreshToken = redisTemplate.opsForValue().get(refreshTokenKey); return Objects.equals(requestedRefreshToken, foundRefreshToken); @@ -46,7 +47,7 @@ public void deleteRefreshTokenByAccessToken(AccessToken accessToken) { } public Subject parseSubject(String token) { - String subject = JwtUtils.parseSubject(token, jwtProperties.secret()); + String subject = tokenProvider.parseSubject(token, jwtProperties.secret()); return new Subject(subject); } diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java index c6bee80ab..1775be40d 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java @@ -8,6 +8,7 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; @@ -19,22 +20,18 @@ import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_INVALID; import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_NOT_ISSUED_BY_SERVER; -import static com.example.solidconnection.util.JwtUtils.parseClaims; -import static com.example.solidconnection.util.JwtUtils.parseSubject; @Component -public class EmailSignUpTokenProvider extends TokenProvider { +@RequiredArgsConstructor +public class EmailSignUpTokenProvider { static final String PASSWORD_CLAIM_KEY = "password"; static final String AUTH_TYPE_CLAIM_KEY = "authType"; private final PasswordEncoder passwordEncoder; - - public EmailSignUpTokenProvider(JwtProperties jwtProperties, RedisTemplate redisTemplate, - PasswordEncoder passwordEncoder) { - super(jwtProperties, redisTemplate); - this.passwordEncoder = passwordEncoder; - } + private final JwtProperties jwtProperties; + private final RedisTemplate redisTemplate; + private final TokenProvider tokenProvider; public String generateAndSaveSignUpToken(EmailSignUpTokenRequest request) { String email = request.email(); @@ -54,7 +51,7 @@ public String generateAndSaveSignUpToken(EmailSignUpTokenRequest request) { .setExpiration(expiredDate) .signWith(SignatureAlgorithm.HS512, jwtProperties.secret()) .compact(); - return saveToken(signUpToken, TokenType.SIGN_UP); + return tokenProvider.saveToken(signUpToken, TokenType.SIGN_UP); } public void validateSignUpToken(String token) { @@ -65,7 +62,7 @@ public void validateSignUpToken(String token) { private void validateFormatAndExpiration(String token) { try { - Claims claims = parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); Objects.requireNonNull(claims.getSubject()); String encodedPassword = claims.get(PASSWORD_CLAIM_KEY, String.class); Objects.requireNonNull(encodedPassword); @@ -82,11 +79,11 @@ private void validateIssuedByServer(String email) { } public String parseEmail(String token) { - return parseSubject(token, jwtProperties.secret()); + return tokenProvider.parseSubject(token, jwtProperties.secret()); } public String parseEncodedPassword(String token) { - Claims claims = parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); return claims.get(PASSWORD_CLAIM_KEY, String.class); } } diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java index 8fa290d30..58ab5ac6f 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java @@ -8,6 +8,7 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; @@ -18,17 +19,16 @@ import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_INVALID; import static com.example.solidconnection.common.exception.ErrorCode.SIGN_UP_TOKEN_NOT_ISSUED_BY_SERVER; -import static com.example.solidconnection.util.JwtUtils.parseClaims; -import static com.example.solidconnection.util.JwtUtils.parseSubject; @Component -public class OAuthSignUpTokenProvider extends TokenProvider { +@RequiredArgsConstructor +public class OAuthSignUpTokenProvider { static final String AUTH_TYPE_CLAIM_KEY = "authType"; - public OAuthSignUpTokenProvider(JwtProperties jwtProperties, RedisTemplate redisTemplate) { - super(jwtProperties, redisTemplate); - } + private final JwtProperties jwtProperties; + private final RedisTemplate redisTemplate; + private final TokenProvider tokenProvider; public String generateAndSaveSignUpToken(String email, AuthType authType) { Map authTypeClaim = new HashMap<>(Map.of(AUTH_TYPE_CLAIM_KEY, authType)); @@ -42,7 +42,7 @@ public String generateAndSaveSignUpToken(String email, AuthType authType) { .setExpiration(expiredDate) .signWith(SignatureAlgorithm.HS512, jwtProperties.secret()) .compact(); - return saveToken(signUpToken, TokenType.SIGN_UP); + return tokenProvider.saveToken(signUpToken, TokenType.SIGN_UP); } public void validateSignUpToken(String token) { @@ -53,7 +53,7 @@ public void validateSignUpToken(String token) { private void validateFormatAndExpiration(String token) { try { - Claims claims = parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); Objects.requireNonNull(claims.getSubject()); String serializedAuthType = claims.get(AUTH_TYPE_CLAIM_KEY, String.class); AuthType.valueOf(serializedAuthType); @@ -70,11 +70,11 @@ private void validateIssuedByServer(String email) { } public String parseEmail(String token) { - return parseSubject(token, jwtProperties.secret()); + return tokenProvider.parseSubject(token, jwtProperties.secret()); } public AuthType parseAuthType(String token) { - Claims claims = parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); String authTypeStr = claims.get(AUTH_TYPE_CLAIM_KEY, String.class); return AuthType.valueOf(authTypeStr); } From 28deb3de5e264a0e46fd52cb7cfc12fc93b83b94 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 02:54:24 +0900 Subject: [PATCH 07/17] =?UTF-8?q?refactor:=20JwtUtils=EB=A5=BC=20=EC=93=B0?= =?UTF-8?q?=EB=8D=98=20=EA=B3=B3=EC=97=90=EC=84=9C=20TokenProvider=20?= =?UTF-8?q?=EC=93=B0=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/CommonSignUpTokenProvider.java | 4 ++-- .../security/provider/SiteUserAuthenticationProvider.java | 5 +++-- .../solidconnection/auth/service/SignInServiceTest.java | 8 +++++--- .../auth/service/oauth/OAuthSignUpTokenProviderTest.java | 7 +++++-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java index d16cb5134..7df8a6970 100644 --- a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java @@ -3,7 +3,6 @@ import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.security.config.JwtProperties; import com.example.solidconnection.siteuser.domain.AuthType; -import com.example.solidconnection.util.JwtUtils; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @@ -15,10 +14,11 @@ public class CommonSignUpTokenProvider { private final JwtProperties jwtProperties; + private final TokenProvider tokenProvider; public AuthType parseAuthType(String signUpToken) { try { - String authTypeStr = JwtUtils.parseClaims(signUpToken, jwtProperties.secret()).get(AUTH_TYPE_CLAIM_KEY, String.class); + String authTypeStr = tokenProvider.parseClaims(signUpToken, jwtProperties.secret()).get(AUTH_TYPE_CLAIM_KEY, String.class); return AuthType.valueOf(authTypeStr); } catch (Exception e) { throw new CustomException(SIGN_UP_TOKEN_INVALID); diff --git a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java index 6ce43b97c..ad39fa7ac 100644 --- a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java +++ b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java @@ -1,5 +1,6 @@ package com.example.solidconnection.security.provider; +import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.security.authentication.JwtAuthentication; import com.example.solidconnection.security.authentication.SiteUserAuthentication; import com.example.solidconnection.security.config.JwtProperties; @@ -11,7 +12,6 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; -import static com.example.solidconnection.util.JwtUtils.parseSubject; @Component @RequiredArgsConstructor @@ -19,13 +19,14 @@ public class SiteUserAuthenticationProvider implements AuthenticationProvider { private final JwtProperties jwtProperties; private final SiteUserDetailsService siteUserDetailsService; + private final TokenProvider tokenProvider; @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { JwtAuthentication jwtAuth = (JwtAuthentication) auth; String token = jwtAuth.getToken(); - String username = parseSubject(token, jwtProperties.secret()); + String username = tokenProvider.parseSubject(token, jwtProperties.secret()); SiteUserDetails userDetails = (SiteUserDetails) siteUserDetailsService.loadUserByUsername(username); return new SiteUserAuthentication(token, userDetails); } diff --git a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java index 1656ed4e5..9428368f5 100644 --- a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java @@ -6,7 +6,6 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; -import com.example.solidconnection.util.JwtUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -25,6 +24,9 @@ class SignInServiceTest { @Autowired private SignInService signInService; + @Autowired + private TokenProvider tokenProvider; + @Autowired private JwtProperties jwtProperties; @@ -49,8 +51,8 @@ void setUp() { SignInResponse signInResponse = signInService.signIn(user); // then - String accessTokenSubject = JwtUtils.parseSubject(signInResponse.accessToken(), jwtProperties.secret()); - String refreshTokenSubject = JwtUtils.parseSubject(signInResponse.refreshToken(), jwtProperties.secret()); + String accessTokenSubject = tokenProvider.parseSubject(signInResponse.accessToken(), jwtProperties.secret()); + String refreshTokenSubject = tokenProvider.parseSubject(signInResponse.refreshToken(), jwtProperties.secret()); String savedRefreshToken = redisTemplate.opsForValue().get(TokenType.REFRESH.addPrefix(refreshTokenSubject)); assertAll( () -> assertThat(accessTokenSubject).isEqualTo(subject), diff --git a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java index 233317458..76b282eee 100644 --- a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java @@ -1,11 +1,11 @@ package com.example.solidconnection.auth.service.oauth; import com.example.solidconnection.auth.domain.TokenType; +import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.security.config.JwtProperties; import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.support.TestContainerSpringBootTest; -import com.example.solidconnection.util.JwtUtils; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; @@ -34,6 +34,9 @@ class OAuthSignUpTokenProviderTest { @Autowired private OAuthSignUpTokenProvider OAuthSignUpTokenProvider; + @Autowired + private TokenProvider tokenProvider; + @Autowired private RedisTemplate redisTemplate; @@ -50,7 +53,7 @@ class OAuthSignUpTokenProviderTest { String signUpToken = OAuthSignUpTokenProvider.generateAndSaveSignUpToken(email, authType); // then - Claims claims = JwtUtils.parseClaims(signUpToken, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(signUpToken, jwtProperties.secret()); String actualSubject = claims.getSubject(); AuthType actualAuthType = AuthType.valueOf(claims.get(AUTH_TYPE_CLAIM_KEY, String.class)); String signUpTokenKey = TokenType.SIGN_UP.addPrefix(email); From ed4f4ce12326b9246b8a3e327ba5bd3dcaae01a0 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 03:20:13 +0900 Subject: [PATCH 08/17] =?UTF-8?q?refactor:=20TokenProvider=EC=9D=98=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9D=B8=EC=9E=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AS-IS: JwtUtils에 정의된 xxxParse 함수를 사용하기 위해서는, 함수 자체가 static이라서 호출하는 곳으로부터 jwt 시크릿 키를 건네받아야했다. 이를 위해 여러곳에서 JwtProperties를 주입받아 jwtProperties.secret()을 호출하며 xxxParse()함수에 값을 넘겨줬다. - TO-BE: TokenProvider를 컴포넌트로 만듦으로서, TokenProvider의 내부에서 jwt 시크릿 키를 주입받을 수 있게 되었다. 함수의 인자로 시크릿키를 받을 필요가 없게 되었으므로 함수 인자를 수정한다. --- .../auth/service/AuthTokenProvider.java | 6 ++---- .../auth/service/CommonSignUpTokenProvider.java | 4 +--- .../auth/service/EmailSignUpTokenProvider.java | 6 +++--- .../solidconnection/auth/service/TokenProvider.java | 10 +++++----- .../auth/service/oauth/OAuthSignUpTokenProvider.java | 6 +++--- .../provider/SiteUserAuthenticationProvider.java | 4 +--- .../auth/service/SignInServiceTest.java | 4 ++-- .../service/oauth/OAuthSignUpTokenProviderTest.java | 2 +- 8 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java index 19a64a5e1..4c0b005d7 100644 --- a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java @@ -1,7 +1,6 @@ package com.example.solidconnection.auth.service; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.security.config.JwtProperties; import com.example.solidconnection.siteuser.domain.SiteUser; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; @@ -13,7 +12,6 @@ @RequiredArgsConstructor public class AuthTokenProvider { - private final JwtProperties jwtProperties; private final RedisTemplate redisTemplate; private final TokenProvider tokenProvider; @@ -34,7 +32,7 @@ public RefreshToken generateAndSaveRefreshToken(Subject subject) { * - 조회된 리프레시 토큰과 요청된 토큰이 같은지 비교한다. * */ public boolean isValidRefreshToken(String requestedRefreshToken) { - String subject = tokenProvider.parseSubject(requestedRefreshToken, jwtProperties.secret()); + String subject = tokenProvider.parseSubject(requestedRefreshToken); String refreshTokenKey = TokenType.REFRESH.addPrefix(subject); String foundRefreshToken = redisTemplate.opsForValue().get(refreshTokenKey); return Objects.equals(requestedRefreshToken, foundRefreshToken); @@ -47,7 +45,7 @@ public void deleteRefreshTokenByAccessToken(AccessToken accessToken) { } public Subject parseSubject(String token) { - String subject = tokenProvider.parseSubject(token, jwtProperties.secret()); + String subject = tokenProvider.parseSubject(token); return new Subject(subject); } diff --git a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java index 7df8a6970..d1ebe3b52 100644 --- a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java @@ -1,7 +1,6 @@ package com.example.solidconnection.auth.service; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.security.config.JwtProperties; import com.example.solidconnection.siteuser.domain.AuthType; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @@ -13,12 +12,11 @@ @RequiredArgsConstructor public class CommonSignUpTokenProvider { - private final JwtProperties jwtProperties; private final TokenProvider tokenProvider; public AuthType parseAuthType(String signUpToken) { try { - String authTypeStr = tokenProvider.parseClaims(signUpToken, jwtProperties.secret()).get(AUTH_TYPE_CLAIM_KEY, String.class); + String authTypeStr = tokenProvider.parseClaims(signUpToken).get(AUTH_TYPE_CLAIM_KEY, String.class); return AuthType.valueOf(authTypeStr); } catch (Exception e) { throw new CustomException(SIGN_UP_TOKEN_INVALID); diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java index 1775be40d..e01df08dc 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java @@ -62,7 +62,7 @@ public void validateSignUpToken(String token) { private void validateFormatAndExpiration(String token) { try { - Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token); Objects.requireNonNull(claims.getSubject()); String encodedPassword = claims.get(PASSWORD_CLAIM_KEY, String.class); Objects.requireNonNull(encodedPassword); @@ -79,11 +79,11 @@ private void validateIssuedByServer(String email) { } public String parseEmail(String token) { - return tokenProvider.parseSubject(token, jwtProperties.secret()); + return tokenProvider.parseSubject(token); } public String parseEncodedPassword(String token) { - Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token); return claims.get(PASSWORD_CLAIM_KEY, String.class); } } diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java index 553480687..5d84cc69c 100644 --- a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java @@ -36,7 +36,7 @@ public final String generateToken(String string, TokenType tokenType) { } public final String saveToken(String token, TokenType tokenType) { - String subject = parseSubject(token, jwtProperties.secret()); + String subject = parseSubject(token); redisTemplate.opsForValue().set( tokenType.addPrefix(subject), token, @@ -46,17 +46,17 @@ public final String saveToken(String token, TokenType tokenType) { return token; } - public String parseSubject(String token, String secretKey) { + public String parseSubject(String token) { try { - return parseClaims(token, secretKey).getSubject(); + return parseClaims(token).getSubject(); } catch (Exception e) { throw new CustomException(INVALID_TOKEN); } } - public Claims parseClaims(String token, String secretKey) throws ExpiredJwtException { + public Claims parseClaims(String token) throws ExpiredJwtException { return Jwts.parser() - .setSigningKey(secretKey) + .setSigningKey(jwtProperties.secret()) .parseClaimsJws(token) .getBody(); } diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java index 58ab5ac6f..b3a34eb31 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java @@ -53,7 +53,7 @@ public void validateSignUpToken(String token) { private void validateFormatAndExpiration(String token) { try { - Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token); Objects.requireNonNull(claims.getSubject()); String serializedAuthType = claims.get(AUTH_TYPE_CLAIM_KEY, String.class); AuthType.valueOf(serializedAuthType); @@ -70,11 +70,11 @@ private void validateIssuedByServer(String email) { } public String parseEmail(String token) { - return tokenProvider.parseSubject(token, jwtProperties.secret()); + return tokenProvider.parseSubject(token); } public AuthType parseAuthType(String token) { - Claims claims = tokenProvider.parseClaims(token, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(token); String authTypeStr = claims.get(AUTH_TYPE_CLAIM_KEY, String.class); return AuthType.valueOf(authTypeStr); } diff --git a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java index ad39fa7ac..dfa3fe230 100644 --- a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java +++ b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java @@ -3,7 +3,6 @@ import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.security.authentication.JwtAuthentication; import com.example.solidconnection.security.authentication.SiteUserAuthentication; -import com.example.solidconnection.security.config.JwtProperties; import com.example.solidconnection.security.userdetails.SiteUserDetails; import com.example.solidconnection.security.userdetails.SiteUserDetailsService; import lombok.RequiredArgsConstructor; @@ -17,7 +16,6 @@ @RequiredArgsConstructor public class SiteUserAuthenticationProvider implements AuthenticationProvider { - private final JwtProperties jwtProperties; private final SiteUserDetailsService siteUserDetailsService; private final TokenProvider tokenProvider; @@ -26,7 +24,7 @@ public Authentication authenticate(Authentication auth) throws AuthenticationExc JwtAuthentication jwtAuth = (JwtAuthentication) auth; String token = jwtAuth.getToken(); - String username = tokenProvider.parseSubject(token, jwtProperties.secret()); + String username = tokenProvider.parseSubject(token); SiteUserDetails userDetails = (SiteUserDetails) siteUserDetailsService.loadUserByUsername(username); return new SiteUserAuthentication(token, userDetails); } diff --git a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java index 9428368f5..18f72e0fe 100644 --- a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java @@ -51,8 +51,8 @@ void setUp() { SignInResponse signInResponse = signInService.signIn(user); // then - String accessTokenSubject = tokenProvider.parseSubject(signInResponse.accessToken(), jwtProperties.secret()); - String refreshTokenSubject = tokenProvider.parseSubject(signInResponse.refreshToken(), jwtProperties.secret()); + String accessTokenSubject = tokenProvider.parseSubject(signInResponse.accessToken()); + String refreshTokenSubject = tokenProvider.parseSubject(signInResponse.refreshToken()); String savedRefreshToken = redisTemplate.opsForValue().get(TokenType.REFRESH.addPrefix(refreshTokenSubject)); assertAll( () -> assertThat(accessTokenSubject).isEqualTo(subject), diff --git a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java index 76b282eee..755eb6e2d 100644 --- a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java @@ -53,7 +53,7 @@ class OAuthSignUpTokenProviderTest { String signUpToken = OAuthSignUpTokenProvider.generateAndSaveSignUpToken(email, authType); // then - Claims claims = tokenProvider.parseClaims(signUpToken, jwtProperties.secret()); + Claims claims = tokenProvider.parseClaims(signUpToken); String actualSubject = claims.getSubject(); AuthType actualAuthType = AuthType.valueOf(claims.get(AUTH_TYPE_CLAIM_KEY, String.class)); String signUpTokenKey = TokenType.SIGN_UP.addPrefix(email); From 9ceb6d2d8daaa518fd42cd18201cf5c5ffa62bad Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 04:12:37 +0900 Subject: [PATCH 09/17] =?UTF-8?q?test:=20TokenProvider=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AS-IS : TokenProvider가 추상 클래스일 때는 이를 상속하는 클래스들로 TokenProvider의 기능을 테스트했다. - TO-BE : TokenProvider도 컴포넌트가 되었으므로, 테스트 코드를 작성한다. --- .../auth/service/TokenProviderTest.java | 175 ++++++++++++++++++ .../solidconnection/util/JwtUtilsTest.java | 68 ------- 2 files changed, 175 insertions(+), 68 deletions(-) create mode 100644 src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java delete mode 100644 src/test/java/com/example/solidconnection/util/JwtUtilsTest.java diff --git a/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java new file mode 100644 index 000000000..a4f48dafa --- /dev/null +++ b/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java @@ -0,0 +1,175 @@ +package com.example.solidconnection.auth.service; + +import com.example.solidconnection.auth.domain.TokenType; +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; +import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.support.TestContainerSpringBootTest; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertAll; + +@DisplayName("토큰 제공자 테스트") +@TestContainerSpringBootTest +class TokenProviderTest { + + @Autowired + private TokenProvider tokenProvider; + + @Autowired + private JwtProperties jwtProperties; + + @Autowired + private RedisTemplate redisTemplate; + + @Test + void 토큰을_생성한다() { + // given + String actualSubject = "subject123"; + TokenType actualTokenType = TokenType.ACCESS; + + // when + String token = tokenProvider.generateToken(actualSubject, actualTokenType); + + // then - subject와 만료 시간이 일치하는지 검증 + Claims claims = tokenProvider.parseClaims(token); + long expectedExpireTime = claims.getExpiration().getTime() - claims.getIssuedAt().getTime(); + assertAll( + () -> assertThat(claims.getSubject()).isEqualTo(actualSubject), + () -> assertThat(expectedExpireTime).isEqualTo(actualTokenType.getExpireTime()) + ); + } + + @Test + void 토큰을_저장한다() { + // given + String subject = "subject123"; + TokenType tokenType = TokenType.ACCESS; + String token = tokenProvider.generateToken(subject, tokenType); + + // when + String savedToken = tokenProvider.saveToken(token, tokenType); + + // then - key: "{TokenType.Prefix}:subject", value: {token} 로 저장되어있는지 검증, 반환하는 값이 value와 같은지 검증 + String key = tokenType.addPrefix(subject); + String value = redisTemplate.opsForValue().get(key); + assertAll( + () -> assertThat(value).isEqualTo(token), + () -> assertThat(savedToken).isEqualTo(value) + ); + } + + @Nested + class 토큰으로부터_subject_를_추출한다 { + + @Test + void 유효한_토큰의_subject_를_추출한다() { + // given + String subject = "subject000"; + String token = createValidToken(subject); + + // when + String extractedSubject = tokenProvider.parseSubject(token); + + // then + assertThat(extractedSubject).isEqualTo(subject); + } + + @Test + void 유효하지_않은_토큰의_subject_를_추출하면_예외_응답을_반환한다() { + // given + String subject = "subject123"; + String token = createExpiredToken(subject); + + // when, then + assertThatCode(() -> tokenProvider.parseSubject(token)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.INVALID_TOKEN.getMessage()); + } + } + + @Nested + class 토큰으로부터_claim_을_추출한다 { + + @Test + void 유효한_토큰의_claim_을_추출한다() { + // given + String subject = "subject"; + String claimKey = "key"; + String claimValue = "value"; + Claims expectedClaims = Jwts.claims(new HashMap<>(Map.of(claimKey, claimValue))).setSubject(subject); + String token = createValidToken(expectedClaims); + + // when + Claims actualClaims = tokenProvider.parseClaims(token); + + // then + assertAll( + () -> assertThat(actualClaims.getSubject()).isEqualTo(subject), + () -> assertThat(actualClaims.get(claimKey)).isEqualTo(claimValue) + ); + } + + @Test + void 유효하지_않은_토큰의_claim_을_추출하면_예외_응답을_반환한다() { + // given + String subject = "subject"; + Claims expectedClaims = Jwts.claims().setSubject(subject); + String token = createExpiredToken(expectedClaims); + + // when + assertThatCode(() -> tokenProvider.parseClaims(token)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.INVALID_TOKEN.getMessage()); + } + } + + private String createValidToken(String subject) { + return Jwts.builder() + .setSubject(subject) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + 1000)) + .signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) + .compact(); + } + + private String createValidToken(Claims claims) { + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() + 1000)) + .signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) + .compact(); + } + + private String createExpiredToken(String subject) { + return Jwts.builder() + .setSubject(subject) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() - 1000)) + .signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) + .compact(); + } + + private String createExpiredToken(Claims claims) { + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(new Date()) + .setExpiration(new Date(System.currentTimeMillis() - 1000)) + .signWith(SignatureAlgorithm.HS256, jwtProperties.secret()) + .compact(); + } +} diff --git a/src/test/java/com/example/solidconnection/util/JwtUtilsTest.java b/src/test/java/com/example/solidconnection/util/JwtUtilsTest.java deleted file mode 100644 index 28116322f..000000000 --- a/src/test/java/com/example/solidconnection/util/JwtUtilsTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.example.solidconnection.util; - -import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.common.exception.ErrorCode; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.util.Date; - -import static com.example.solidconnection.util.JwtUtils.parseSubject; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; - -@DisplayName("JwtUtils 테스트") -class JwtUtilsTest { - - private final String jwtSecretKey = "jwt-secret-key"; - - @Nested - class 토큰으로부터_subject_를_추출한다 { - - @Test - void 유효한_토큰의_subject_를_추출한다() { - // given - String subject = "subject000"; - String token = createValidToken(subject); - - // when - String extractedSubject = parseSubject(token, jwtSecretKey); - - // then - assertThat(extractedSubject).isEqualTo(subject); - } - - @Test - void 유효하지_않은_토큰의_subject_를_추출하면_예외_응답을_반환한다() { - // given - String subject = "subject123"; - String token = createExpiredToken(subject); - - // when - assertThatCode(() -> parseSubject(token, jwtSecretKey)) - .isInstanceOf(CustomException.class) - .hasMessage(ErrorCode.INVALID_TOKEN.getMessage()); - } - } - - private String createValidToken(String subject) { - return Jwts.builder() - .setSubject(subject) - .setIssuedAt(new Date()) - .setExpiration(new Date(System.currentTimeMillis() + 1000)) - .signWith(SignatureAlgorithm.HS256, jwtSecretKey) - .compact(); - } - - private String createExpiredToken(String subject) { - return Jwts.builder() - .setSubject(subject) - .setIssuedAt(new Date()) - .setExpiration(new Date(System.currentTimeMillis() - 1000)) - .signWith(SignatureAlgorithm.HS256, jwtSecretKey) - .compact(); - } -} From 578db3e807f56836b74a46385a95832122a7bfdc Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 04:13:31 +0900 Subject: [PATCH 10/17] =?UTF-8?q?refactor:=20=EB=8D=94=20=EC=9E=91?= =?UTF-8?q?=EC=9D=80=20=EC=9E=91=EC=97=85=EC=97=90=EC=84=9C=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EB=A5=BC=20=EB=B0=9C=EC=83=9D=EC=8B=9C=ED=82=A4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - parseSubject가 parseClaims를 호출하는데, 이들이 발생시키는 예외의 종류가 다르면 안된다. --- .../auth/service/TokenProvider.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java index 5d84cc69c..7124bedae 100644 --- a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java @@ -4,7 +4,6 @@ import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.security.config.JwtProperties; import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import lombok.RequiredArgsConstructor; @@ -47,17 +46,17 @@ public final String saveToken(String token, TokenType tokenType) { } public String parseSubject(String token) { + return parseClaims(token).getSubject(); + } + + public Claims parseClaims(String token) { try { - return parseClaims(token).getSubject(); + return Jwts.parser() + .setSigningKey(jwtProperties.secret()) + .parseClaimsJws(token) + .getBody(); } catch (Exception e) { throw new CustomException(INVALID_TOKEN); } } - - public Claims parseClaims(String token) throws ExpiredJwtException { - return Jwts.parser() - .setSigningKey(jwtProperties.secret()) - .parseClaimsJws(token) - .getBody(); - } } From ac0d81ef54f19abd3b64f01234208d3eed46c1ed Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 04:13:53 +0900 Subject: [PATCH 11/17] =?UTF-8?q?chore:=20=EA=B0=9C=ED=96=89=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20=EC=95=88=EC=93=B0=EB=8A=94=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/auth/service/AuthTokenProviderTest.java | 2 +- .../solidconnection/auth/service/SignInServiceTest.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java index f13f24616..b53e79ef7 100644 --- a/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java @@ -71,7 +71,7 @@ class 리프레시_토큰을_제공한다 { } @Test - void 액세서_토큰에_해당하는_리프레시_토큰을_삭제한다() { + void 액세스_토큰에_해당하는_리프레시_토큰을_삭제한다() { // given authTokenProvider.generateAndSaveRefreshToken(subject); AccessToken accessToken = authTokenProvider.generateAccessToken(subject); diff --git a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java index 18f72e0fe..463bc4957 100644 --- a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java @@ -2,7 +2,6 @@ import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.SignInResponse; -import com.example.solidconnection.security.config.JwtProperties; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; @@ -27,9 +26,6 @@ class SignInServiceTest { @Autowired private TokenProvider tokenProvider; - @Autowired - private JwtProperties jwtProperties; - @Autowired private RedisTemplate redisTemplate; From a10c991379d4bb18b917c2afe90885f828f9bb27 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 04:15:55 +0900 Subject: [PATCH 12/17] =?UTF-8?q?refactor:=20=EC=A0=9C=EB=8C=80=EB=A1=9C?= =?UTF-8?q?=20=EB=90=9C=20DIP=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - security가 auth를 의존하지 않게 하기 위해, BlackListChecker 인터페이스를 security패키지 내부로 옮긴다. --- .../solidconnection/auth/service/TokenBlackListService.java | 1 + .../{auth/service => security/filter}/BlacklistChecker.java | 2 +- .../solidconnection/security/filter/SignOutCheckFilter.java | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/example/solidconnection/{auth/service => security/filter}/BlacklistChecker.java (61%) diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java b/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java index 39612c85b..b81837d7e 100644 --- a/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java +++ b/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java @@ -1,5 +1,6 @@ package com.example.solidconnection.auth.service; +import com.example.solidconnection.security.filter.BlacklistChecker; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/com/example/solidconnection/auth/service/BlacklistChecker.java b/src/main/java/com/example/solidconnection/security/filter/BlacklistChecker.java similarity index 61% rename from src/main/java/com/example/solidconnection/auth/service/BlacklistChecker.java rename to src/main/java/com/example/solidconnection/security/filter/BlacklistChecker.java index b4e174906..f093d8e8f 100644 --- a/src/main/java/com/example/solidconnection/auth/service/BlacklistChecker.java +++ b/src/main/java/com/example/solidconnection/security/filter/BlacklistChecker.java @@ -1,4 +1,4 @@ -package com.example.solidconnection.auth.service; +package com.example.solidconnection.security.filter; public interface BlacklistChecker { diff --git a/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java b/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java index afe1294bd..c3926d67f 100644 --- a/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java +++ b/src/main/java/com/example/solidconnection/security/filter/SignOutCheckFilter.java @@ -1,6 +1,5 @@ package com.example.solidconnection.security.filter; -import com.example.solidconnection.auth.service.BlacklistChecker; import com.example.solidconnection.common.exception.CustomException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; From 2eddf887dbb217f6acf4a7cd13a9c4735151778e Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 20 May 2025 18:31:53 +0900 Subject: [PATCH 13/17] =?UTF-8?q?chore:=20todo=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/solidconnection/auth/service/AuthServiceTest.java | 4 ++-- .../solidconnection/auth/service/AuthTokenProviderTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java index acf969540..f39c573f1 100644 --- a/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java @@ -43,7 +43,7 @@ class AuthServiceTest { void 로그아웃한다() { // given Subject subject = new Subject("subject"); - AccessToken accessToken = authTokenProvider.generateAccessToken(subject); // todo: #296 + AccessToken accessToken = authTokenProvider.generateAccessToken(subject); // when authService.signOut(accessToken.token()); @@ -61,7 +61,7 @@ class AuthServiceTest { // given SiteUser user = siteUserFixture.사용자(); Subject subject = authTokenProvider.toSubject(user); - AccessToken accessToken = authTokenProvider.generateAccessToken(subject); // todo: #296 + AccessToken accessToken = authTokenProvider.generateAccessToken(subject); // when authService.quit(user, accessToken.token()); diff --git a/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java index b53e79ef7..b6c111f24 100644 --- a/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/AuthTokenProviderTest.java @@ -61,7 +61,7 @@ class 리프레시_토큰을_제공한다 { void 유효한_리프레시_토큰인지_확인한다() { // given RefreshToken refreshToken = authTokenProvider.generateAndSaveRefreshToken(subject); - AccessToken fakeRefreshToken = authTokenProvider.generateAccessToken(subject); // todo: issue#296 + AccessToken fakeRefreshToken = authTokenProvider.generateAccessToken(subject); // when, then assertAll( From e0da40bf1e970e6f12ecbc65d1ea72ba5c792b82 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 21 May 2025 19:34:30 +0900 Subject: [PATCH 14/17] =?UTF-8?q?refactor:=20jwt=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=BD=94=EB=93=9C=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TokenProvider, TokenBlackListService를 auth.token 으로 - JwtProperties를 auth.token.config 로 --- .../com/example/solidconnection/auth/service/AuthService.java | 1 + .../solidconnection/auth/service/AuthTokenProvider.java | 1 + .../auth/service/CommonSignUpTokenProvider.java | 1 + .../auth/service/EmailSignUpTokenProvider.java | 3 ++- .../auth/service/oauth/OAuthSignUpTokenProvider.java | 4 ++-- .../auth/{service => token}/TokenBlackListService.java | 3 ++- .../auth/{service => token}/TokenProvider.java | 4 ++-- .../{security => auth/token}/config/JwtProperties.java | 2 +- .../security/provider/SiteUserAuthenticationProvider.java | 2 +- .../example/solidconnection/auth/service/AuthServiceTest.java | 1 + .../solidconnection/auth/service/SignInServiceTest.java | 1 + .../auth/service/TokenBlackListServiceTest.java | 1 + .../solidconnection/auth/service/TokenProviderTest.java | 3 ++- .../auth/service/oauth/OAuthSignUpTokenProviderTest.java | 4 ++-- .../security/filter/JwtAuthenticationFilterTest.java | 2 +- .../security/filter/SignOutCheckFilterTest.java | 2 +- .../security/provider/SiteUserAuthenticationProviderTest.java | 2 +- 17 files changed, 23 insertions(+), 14 deletions(-) rename src/main/java/com/example/solidconnection/auth/{service => token}/TokenBlackListService.java (91%) rename src/main/java/com/example/solidconnection/auth/{service => token}/TokenProvider.java (94%) rename src/main/java/com/example/solidconnection/{security => auth/token}/config/JwtProperties.java (75%) diff --git a/src/main/java/com/example/solidconnection/auth/service/AuthService.java b/src/main/java/com/example/solidconnection/auth/service/AuthService.java index 2189960d8..6053e8716 100644 --- a/src/main/java/com/example/solidconnection/auth/service/AuthService.java +++ b/src/main/java/com/example/solidconnection/auth/service/AuthService.java @@ -2,6 +2,7 @@ import com.example.solidconnection.auth.dto.ReissueRequest; import com.example.solidconnection.auth.dto.ReissueResponse; +import com.example.solidconnection.auth.token.TokenBlackListService; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.SiteUser; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java index 4c0b005d7..7e509314e 100644 --- a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java @@ -1,6 +1,7 @@ package com.example.solidconnection.auth.service; import com.example.solidconnection.auth.domain.TokenType; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.siteuser.domain.SiteUser; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; diff --git a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java index d1ebe3b52..feda1199e 100644 --- a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java @@ -1,5 +1,6 @@ package com.example.solidconnection.auth.service; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.AuthType; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java index e01df08dc..9f226d82e 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java @@ -2,8 +2,9 @@ import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.EmailSignUpTokenRequest; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.siteuser.domain.AuthType; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java index b3a34eb31..b7394002e 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java @@ -1,9 +1,9 @@ package com.example.solidconnection.auth.service.oauth; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.service.TokenProvider; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.siteuser.domain.AuthType; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java b/src/main/java/com/example/solidconnection/auth/token/TokenBlackListService.java similarity index 91% rename from src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java rename to src/main/java/com/example/solidconnection/auth/token/TokenBlackListService.java index b81837d7e..4175a577f 100644 --- a/src/main/java/com/example/solidconnection/auth/service/TokenBlackListService.java +++ b/src/main/java/com/example/solidconnection/auth/token/TokenBlackListService.java @@ -1,5 +1,6 @@ -package com.example.solidconnection.auth.service; +package com.example.solidconnection.auth.token; +import com.example.solidconnection.auth.service.AccessToken; import com.example.solidconnection.security.filter.BlacklistChecker; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java similarity index 94% rename from src/main/java/com/example/solidconnection/auth/service/TokenProvider.java rename to src/main/java/com/example/solidconnection/auth/token/TokenProvider.java index 7124bedae..dfb42cc56 100644 --- a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java @@ -1,8 +1,8 @@ -package com.example.solidconnection.auth.service; +package com.example.solidconnection.auth.token; import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; diff --git a/src/main/java/com/example/solidconnection/security/config/JwtProperties.java b/src/main/java/com/example/solidconnection/auth/token/config/JwtProperties.java similarity index 75% rename from src/main/java/com/example/solidconnection/security/config/JwtProperties.java rename to src/main/java/com/example/solidconnection/auth/token/config/JwtProperties.java index f4afa5245..bf5180218 100644 --- a/src/main/java/com/example/solidconnection/security/config/JwtProperties.java +++ b/src/main/java/com/example/solidconnection/auth/token/config/JwtProperties.java @@ -1,4 +1,4 @@ -package com.example.solidconnection.security.config; +package com.example.solidconnection.auth.token.config; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java index dfa3fe230..81fbc9959 100644 --- a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java +++ b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java @@ -1,6 +1,6 @@ package com.example.solidconnection.security.provider; -import com.example.solidconnection.auth.service.TokenProvider; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.security.authentication.JwtAuthentication; import com.example.solidconnection.security.authentication.SiteUserAuthentication; import com.example.solidconnection.security.userdetails.SiteUserDetails; diff --git a/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java index f39c573f1..c4c2a1708 100644 --- a/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/AuthServiceTest.java @@ -3,6 +3,7 @@ import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.ReissueRequest; import com.example.solidconnection.auth.dto.ReissueResponse; +import com.example.solidconnection.auth.token.TokenBlackListService; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; diff --git a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java index 463bc4957..fe6fe219d 100644 --- a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java @@ -2,6 +2,7 @@ import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.SignInResponse; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; diff --git a/src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java index ffe823df8..e1974cc93 100644 --- a/src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/TokenBlackListServiceTest.java @@ -1,5 +1,6 @@ package com.example.solidconnection.auth.service; +import com.example.solidconnection.auth.token.TokenBlackListService; import com.example.solidconnection.support.TestContainerSpringBootTest; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java index a4f48dafa..bfc25f176 100644 --- a/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java @@ -1,9 +1,10 @@ package com.example.solidconnection.auth.service; import com.example.solidconnection.auth.domain.TokenType; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.common.exception.ErrorCode; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.support.TestContainerSpringBootTest; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; diff --git a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java index 755eb6e2d..a9ade8aa4 100644 --- a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java @@ -1,9 +1,9 @@ package com.example.solidconnection.auth.service.oauth; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.service.TokenProvider; +import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.support.TestContainerSpringBootTest; import io.jsonwebtoken.Claims; diff --git a/src/test/java/com/example/solidconnection/security/filter/JwtAuthenticationFilterTest.java b/src/test/java/com/example/solidconnection/security/filter/JwtAuthenticationFilterTest.java index c66037c82..229fed27b 100644 --- a/src/test/java/com/example/solidconnection/security/filter/JwtAuthenticationFilterTest.java +++ b/src/test/java/com/example/solidconnection/security/filter/JwtAuthenticationFilterTest.java @@ -1,7 +1,7 @@ package com.example.solidconnection.security.filter; import com.example.solidconnection.security.authentication.SiteUserAuthentication; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.security.userdetails.SiteUserDetailsService; import com.example.solidconnection.support.TestContainerSpringBootTest; import io.jsonwebtoken.Jwts; diff --git a/src/test/java/com/example/solidconnection/security/filter/SignOutCheckFilterTest.java b/src/test/java/com/example/solidconnection/security/filter/SignOutCheckFilterTest.java index 5ccc1aa1b..80e927203 100644 --- a/src/test/java/com/example/solidconnection/security/filter/SignOutCheckFilterTest.java +++ b/src/test/java/com/example/solidconnection/security/filter/SignOutCheckFilterTest.java @@ -1,7 +1,7 @@ package com.example.solidconnection.security.filter; import com.example.solidconnection.common.exception.CustomException; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.support.TestContainerSpringBootTest; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; diff --git a/src/test/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProviderTest.java b/src/test/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProviderTest.java index 9c51de838..0bbb6677f 100644 --- a/src/test/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProviderTest.java +++ b/src/test/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProviderTest.java @@ -2,7 +2,7 @@ import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.security.authentication.SiteUserAuthentication; -import com.example.solidconnection.security.config.JwtProperties; +import com.example.solidconnection.auth.token.config.JwtProperties; import com.example.solidconnection.security.userdetails.SiteUserDetails; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; From 20a736470d9723a55ae38282cb203c75d4e586e8 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 21 May 2025 19:37:29 +0900 Subject: [PATCH 15/17] =?UTF-8?q?refactor:=20TokenProvider=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/TokenProvider.java | 15 +++++++++++++++ .../solidconnection/auth/token/TokenProvider.java | 6 +++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/solidconnection/auth/service/TokenProvider.java diff --git a/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java new file mode 100644 index 000000000..2cd93fb8e --- /dev/null +++ b/src/main/java/com/example/solidconnection/auth/service/TokenProvider.java @@ -0,0 +1,15 @@ +package com.example.solidconnection.auth.service; + +import com.example.solidconnection.auth.domain.TokenType; +import io.jsonwebtoken.Claims; + +public interface TokenProvider { + + String generateToken(String string, TokenType tokenType); + + String saveToken(String token, TokenType tokenType); + + String parseSubject(String token); + + Claims parseClaims(String token); +} diff --git a/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java index dfb42cc56..a5d85d035 100644 --- a/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java @@ -17,11 +17,12 @@ @Component @RequiredArgsConstructor -public class TokenProvider { +public class TokenProvider implements com.example.solidconnection.auth.service.TokenProvider { private final JwtProperties jwtProperties; private final RedisTemplate redisTemplate; + @Override public final String generateToken(String string, TokenType tokenType) { Claims claims = Jwts.claims().setSubject(string); Date now = new Date(); @@ -34,6 +35,7 @@ public final String generateToken(String string, TokenType tokenType) { .compact(); } + @Override public final String saveToken(String token, TokenType tokenType) { String subject = parseSubject(token); redisTemplate.opsForValue().set( @@ -45,10 +47,12 @@ public final String saveToken(String token, TokenType tokenType) { return token; } + @Override public String parseSubject(String token) { return parseClaims(token).getSubject(); } + @Override public Claims parseClaims(String token) { try { return Jwts.parser() From 756bb08299682fb0df9466f1ed6848dd6b95efcd Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 21 May 2025 19:43:46 +0900 Subject: [PATCH 16/17] =?UTF-8?q?refactor:=20TokenProvider=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=EC=97=90=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=ED=95=98=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/auth/service/AuthTokenProvider.java | 9 ++++----- .../auth/service/CommonSignUpTokenProvider.java | 1 - .../auth/service/EmailSignUpTokenProvider.java | 3 +-- .../auth/service/oauth/OAuthSignUpTokenProvider.java | 4 ++-- .../token/{TokenProvider.java => JwtTokenProvider.java} | 5 +++-- .../provider/SiteUserAuthenticationProvider.java | 2 +- ...{TokenProviderTest.java => JwtTokenProviderTest.java} | 6 +++--- .../solidconnection/auth/service/SignInServiceTest.java | 1 - .../auth/service/oauth/OAuthSignUpTokenProviderTest.java | 4 ++-- 9 files changed, 16 insertions(+), 19 deletions(-) rename src/main/java/com/example/solidconnection/auth/token/{TokenProvider.java => JwtTokenProvider.java} (94%) rename src/test/java/com/example/solidconnection/auth/service/{TokenProviderTest.java => JwtTokenProviderTest.java} (97%) diff --git a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java index 7e509314e..2ff3e5650 100644 --- a/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/AuthTokenProvider.java @@ -1,7 +1,6 @@ package com.example.solidconnection.auth.service; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.siteuser.domain.SiteUser; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; @@ -28,10 +27,10 @@ public RefreshToken generateAndSaveRefreshToken(Subject subject) { } /* - * 유효한 리프레시 토큰인지 확인한다. - * - 요청된 토큰과 같은 subject 의 리프레시 토큰을 조회한다. - * - 조회된 리프레시 토큰과 요청된 토큰이 같은지 비교한다. - * */ + * 유효한 리프레시 토큰인지 확인한다. + * - 요청된 토큰과 같은 subject 의 리프레시 토큰을 조회한다. + * - 조회된 리프레시 토큰과 요청된 토큰이 같은지 비교한다. + * */ public boolean isValidRefreshToken(String requestedRefreshToken) { String subject = tokenProvider.parseSubject(requestedRefreshToken); String refreshTokenKey = TokenType.REFRESH.addPrefix(subject); diff --git a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java index feda1199e..d1ebe3b52 100644 --- a/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/CommonSignUpTokenProvider.java @@ -1,6 +1,5 @@ package com.example.solidconnection.auth.service; -import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.AuthType; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java index 9f226d82e..fe9a176d3 100644 --- a/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/EmailSignUpTokenProvider.java @@ -2,9 +2,8 @@ import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.EmailSignUpTokenRequest; -import com.example.solidconnection.auth.token.TokenProvider; -import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.auth.token.config.JwtProperties; +import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.AuthType; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; diff --git a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java index b7394002e..1aae0338e 100644 --- a/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProvider.java @@ -1,9 +1,9 @@ package com.example.solidconnection.auth.service.oauth; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.token.TokenProvider; -import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.auth.token.config.JwtProperties; +import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.AuthType; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; diff --git a/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java b/src/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.java similarity index 94% rename from src/main/java/com/example/solidconnection/auth/token/TokenProvider.java rename to src/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.java index a5d85d035..839e58362 100644 --- a/src/main/java/com/example/solidconnection/auth/token/TokenProvider.java +++ b/src/main/java/com/example/solidconnection/auth/token/JwtTokenProvider.java @@ -1,8 +1,9 @@ package com.example.solidconnection.auth.token; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.auth.token.config.JwtProperties; +import com.example.solidconnection.common.exception.CustomException; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @@ -17,7 +18,7 @@ @Component @RequiredArgsConstructor -public class TokenProvider implements com.example.solidconnection.auth.service.TokenProvider { +public class JwtTokenProvider implements TokenProvider { private final JwtProperties jwtProperties; private final RedisTemplate redisTemplate; diff --git a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java index 81fbc9959..dfa3fe230 100644 --- a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java +++ b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java @@ -1,6 +1,6 @@ package com.example.solidconnection.security.provider; -import com.example.solidconnection.auth.token.TokenProvider; +import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.security.authentication.JwtAuthentication; import com.example.solidconnection.security.authentication.SiteUserAuthentication; import com.example.solidconnection.security.userdetails.SiteUserDetails; diff --git a/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/JwtTokenProviderTest.java similarity index 97% rename from src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java rename to src/test/java/com/example/solidconnection/auth/service/JwtTokenProviderTest.java index bfc25f176..c36a0bb39 100644 --- a/src/test/java/com/example/solidconnection/auth/service/TokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/JwtTokenProviderTest.java @@ -1,7 +1,7 @@ package com.example.solidconnection.auth.service; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.token.TokenProvider; +import com.example.solidconnection.auth.token.JwtTokenProvider; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.common.exception.ErrorCode; import com.example.solidconnection.auth.token.config.JwtProperties; @@ -25,10 +25,10 @@ @DisplayName("토큰 제공자 테스트") @TestContainerSpringBootTest -class TokenProviderTest { +class JwtTokenProviderTest { @Autowired - private TokenProvider tokenProvider; + private JwtTokenProvider tokenProvider; @Autowired private JwtProperties jwtProperties; diff --git a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java index fe6fe219d..463bc4957 100644 --- a/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/SignInServiceTest.java @@ -2,7 +2,6 @@ import com.example.solidconnection.auth.domain.TokenType; import com.example.solidconnection.auth.dto.SignInResponse; -import com.example.solidconnection.auth.token.TokenProvider; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; diff --git a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java index a9ade8aa4..c748987c1 100644 --- a/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java +++ b/src/test/java/com/example/solidconnection/auth/service/oauth/OAuthSignUpTokenProviderTest.java @@ -1,9 +1,9 @@ package com.example.solidconnection.auth.service.oauth; import com.example.solidconnection.auth.domain.TokenType; -import com.example.solidconnection.auth.token.TokenProvider; -import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.auth.service.TokenProvider; import com.example.solidconnection.auth.token.config.JwtProperties; +import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.siteuser.domain.AuthType; import com.example.solidconnection.support.TestContainerSpringBootTest; import io.jsonwebtoken.Claims; From d921d2dd1351aec9f6b59046a6cfd68b13749134 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Thu, 22 May 2025 20:28:53 +0900 Subject: [PATCH 17/17] =?UTF-8?q?style:=20=EA=B0=9C=ED=96=89=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/provider/SiteUserAuthenticationProvider.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java index dfa3fe230..a00b77f9a 100644 --- a/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java +++ b/src/main/java/com/example/solidconnection/security/provider/SiteUserAuthenticationProvider.java @@ -11,7 +11,6 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; - @Component @RequiredArgsConstructor public class SiteUserAuthenticationProvider implements AuthenticationProvider {