From 9e2bbe44442f38bed5629a16f71fe8e5635a606e Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Fri, 28 Feb 2025 16:10:36 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=ED=86=A0=ED=81=B0=20=EB=B0=9C?= =?UTF-8?q?=EA=B8=89=20=EC=8B=9C=20=EC=9C=A0=EC=A0=80=20Id=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../swyp8team2/auth/application/AuthService.java | 6 +++--- .../auth/application/jwt/JwtService.java | 9 +++++---- .../auth/presentation/AuthController.java | 15 +++++++++------ .../auth/presentation/dto/AuthResponse.java | 4 ++++ .../auth/presentation/dto/TokenResponse.java | 7 ++++++- .../swyp8team2/common/dev/DataInitializer.java | 4 +++- .../auth/application/AuthServiceTest.java | 4 +++- .../auth/application/JwtServiceTest.java | 7 +++++-- .../auth/presentation/AuthControllerTest.java | 16 ++++++++++------ 9 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/swyp8team2/auth/presentation/dto/AuthResponse.java diff --git a/src/main/java/com/swyp8team2/auth/application/AuthService.java b/src/main/java/com/swyp8team2/auth/application/AuthService.java index 99a4e109..d19a6203 100644 --- a/src/main/java/com/swyp8team2/auth/application/AuthService.java +++ b/src/main/java/com/swyp8team2/auth/application/AuthService.java @@ -7,10 +7,10 @@ import com.swyp8team2.auth.domain.Provider; import com.swyp8team2.auth.domain.SocialAccount; import com.swyp8team2.auth.domain.SocialAccountRepository; +import com.swyp8team2.auth.presentation.dto.TokenResponse; import com.swyp8team2.common.annotation.GuestTokenCryptoService; import com.swyp8team2.crypto.application.CryptoService; import com.swyp8team2.user.application.UserService; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -37,7 +37,7 @@ public AuthService( } @Transactional - public TokenPair oauthSignIn(String code, String redirectUri) { + public TokenResponse oauthSignIn(String code, String redirectUri) { OAuthUserInfo oAuthUserInfo = oAuthService.getUserInfo(code, redirectUri); SocialAccount socialAccount = socialAccountRepository.findBySocialIdAndProvider( oAuthUserInfo.socialId(), @@ -52,7 +52,7 @@ private SocialAccount createUser(OAuthUserInfo oAuthUserInfo) { } @Transactional - public TokenPair reissue(String refreshToken) { + public TokenResponse reissue(String refreshToken) { return jwtService.reissue(refreshToken); } diff --git a/src/main/java/com/swyp8team2/auth/application/jwt/JwtService.java b/src/main/java/com/swyp8team2/auth/application/jwt/JwtService.java index 389e0461..b7963ca8 100644 --- a/src/main/java/com/swyp8team2/auth/application/jwt/JwtService.java +++ b/src/main/java/com/swyp8team2/auth/application/jwt/JwtService.java @@ -2,6 +2,7 @@ import com.swyp8team2.auth.domain.RefreshToken; import com.swyp8team2.auth.domain.RefreshTokenRepository; +import com.swyp8team2.auth.presentation.dto.TokenResponse; import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; import jakarta.transaction.Transactional; @@ -18,7 +19,7 @@ public class JwtService { private final RefreshTokenRepository refreshTokenRepository; @Transactional - public TokenPair createToken(long userId) { + public TokenResponse createToken(long userId) { TokenPair tokenPair = jwtProvider.createToken(new JwtClaim(userId)); RefreshToken refreshToken = refreshTokenRepository.findByUserId(userId) .orElseGet(() -> new RefreshToken(userId, tokenPair.refreshToken())); @@ -27,11 +28,11 @@ public TokenPair createToken(long userId) { log.debug("createToken userId: {} accessToken: {} refreshToken: {}", userId, tokenPair.accessToken(), tokenPair.refreshToken()); - return tokenPair; + return new TokenResponse(tokenPair, userId); } @Transactional - public TokenPair reissue(String refreshToken) { + public TokenResponse reissue(String refreshToken) { JwtClaim claim = jwtProvider.parseToken(refreshToken); RefreshToken findRefreshToken = refreshTokenRepository.findByUserId(claim.idAsLong()) .orElseThrow(() -> new BadRequestException(ErrorCode.REFRESH_TOKEN_NOT_FOUND)); @@ -41,6 +42,6 @@ public TokenPair reissue(String refreshToken) { log.debug("reissue userId: {} accessToken: {} refreshToken: {}", claim.id(), tokenPair.accessToken(), tokenPair.refreshToken()); - return tokenPair; + return new TokenResponse(tokenPair, claim.idAsLong()); } } diff --git a/src/main/java/com/swyp8team2/auth/presentation/AuthController.java b/src/main/java/com/swyp8team2/auth/presentation/AuthController.java index 2bbeaa44..249f2a7d 100644 --- a/src/main/java/com/swyp8team2/auth/presentation/AuthController.java +++ b/src/main/java/com/swyp8team2/auth/presentation/AuthController.java @@ -6,6 +6,7 @@ import com.swyp8team2.auth.presentation.dto.GuestTokenResponse; import com.swyp8team2.auth.presentation.dto.OAuthSignInRequest; import com.swyp8team2.auth.presentation.dto.TokenResponse; +import com.swyp8team2.auth.presentation.dto.AuthResponse; import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; import com.swyp8team2.common.presentation.CustomHeader; @@ -31,28 +32,30 @@ public class AuthController { private final AuthService authService; @PostMapping("/oauth2/code/kakao") - public ResponseEntity kakaoOAuthSignIn( + public ResponseEntity kakaoOAuthSignIn( @Valid @RequestBody OAuthSignInRequest request, HttpServletResponse response ) { - TokenPair tokenPair = authService.oauthSignIn(request.code(), request.redirectUri()); + TokenResponse tokenResponse = authService.oauthSignIn(request.code(), request.redirectUri()); + TokenPair tokenPair = tokenResponse.tokenPair(); Cookie cookie = refreshTokenCookieGenerator.createCookie(tokenPair.refreshToken()); response.addCookie(cookie); - return ResponseEntity.ok(new TokenResponse(tokenPair.accessToken())); + return ResponseEntity.ok(new AuthResponse(tokenPair.accessToken(), tokenResponse.userId())); } @PostMapping("/reissue") - public ResponseEntity reissue( + public ResponseEntity reissue( @CookieValue(name = CustomHeader.CustomCookie.REFRESH_TOKEN, required = false) String refreshToken, HttpServletResponse response ) { if (Objects.isNull(refreshToken)) { throw new BadRequestException(ErrorCode.INVALID_REFRESH_TOKEN_HEADER); } - TokenPair tokenPair = authService.reissue(refreshToken); + TokenResponse tokenResponse = authService.reissue(refreshToken); + TokenPair tokenPair = tokenResponse.tokenPair(); Cookie cookie = refreshTokenCookieGenerator.createCookie(tokenPair.refreshToken()); response.addCookie(cookie); - return ResponseEntity.ok(new TokenResponse(tokenPair.accessToken())); + return ResponseEntity.ok(new AuthResponse(tokenPair.accessToken(), tokenResponse.userId())); } @PostMapping("/guest/token") diff --git a/src/main/java/com/swyp8team2/auth/presentation/dto/AuthResponse.java b/src/main/java/com/swyp8team2/auth/presentation/dto/AuthResponse.java new file mode 100644 index 00000000..65d2c20a --- /dev/null +++ b/src/main/java/com/swyp8team2/auth/presentation/dto/AuthResponse.java @@ -0,0 +1,4 @@ +package com.swyp8team2.auth.presentation.dto; + +public record AuthResponse(String accessToken, Long userId) { +} diff --git a/src/main/java/com/swyp8team2/auth/presentation/dto/TokenResponse.java b/src/main/java/com/swyp8team2/auth/presentation/dto/TokenResponse.java index bb0cf374..dad3501e 100644 --- a/src/main/java/com/swyp8team2/auth/presentation/dto/TokenResponse.java +++ b/src/main/java/com/swyp8team2/auth/presentation/dto/TokenResponse.java @@ -1,4 +1,9 @@ package com.swyp8team2.auth.presentation.dto; -public record TokenResponse(String accessToken) { +import com.swyp8team2.auth.application.jwt.TokenPair; + +public record TokenResponse( + TokenPair tokenPair, + Long userId +) { } diff --git a/src/main/java/com/swyp8team2/common/dev/DataInitializer.java b/src/main/java/com/swyp8team2/common/dev/DataInitializer.java index 1ad636bf..a99ff0f1 100644 --- a/src/main/java/com/swyp8team2/common/dev/DataInitializer.java +++ b/src/main/java/com/swyp8team2/common/dev/DataInitializer.java @@ -2,6 +2,7 @@ import com.swyp8team2.auth.application.jwt.JwtService; import com.swyp8team2.auth.application.jwt.TokenPair; +import com.swyp8team2.auth.presentation.dto.TokenResponse; import com.swyp8team2.comment.domain.Comment; import com.swyp8team2.comment.domain.CommentRepository; import com.swyp8team2.common.annotation.ShareUrlCryptoService; @@ -69,7 +70,8 @@ public void init() { } List adjectives = nicknameAdjectiveRepository.findAll(); User testUser = userRepository.save(User.create("nickname", "https://t1.kakaocdn.net/account_images/default_profile.jpeg")); - TokenPair tokenPair = jwtService.createToken(testUser.getId()); + TokenResponse tokenResponse = jwtService.createToken(testUser.getId()); + TokenPair tokenPair = tokenResponse.tokenPair(); System.out.println("accessToken = " + tokenPair.accessToken()); System.out.println("refreshToken = " + tokenPair.refreshToken()); List users = new ArrayList<>(); diff --git a/src/test/java/com/swyp8team2/auth/application/AuthServiceTest.java b/src/test/java/com/swyp8team2/auth/application/AuthServiceTest.java index 6932bd27..f2e4959e 100644 --- a/src/test/java/com/swyp8team2/auth/application/AuthServiceTest.java +++ b/src/test/java/com/swyp8team2/auth/application/AuthServiceTest.java @@ -7,6 +7,7 @@ import com.swyp8team2.auth.domain.Provider; import com.swyp8team2.auth.domain.SocialAccount; import com.swyp8team2.auth.domain.SocialAccountRepository; +import com.swyp8team2.auth.presentation.dto.TokenResponse; import com.swyp8team2.support.IntegrationTest; import com.swyp8team2.user.domain.User; import com.swyp8team2.user.domain.UserRepository; @@ -52,9 +53,10 @@ void oAuthSignIn() throws Exception { .willReturn(expectedTokenPair); //when - TokenPair tokenPair = authService.oauthSignIn("code", "https://dev.photopic.site"); + TokenResponse tokenResponse = authService.oauthSignIn("code", "https://dev.photopic.site"); //then + TokenPair tokenPair = tokenResponse.tokenPair(); SocialAccount socialAccount = socialAccountRepository.findBySocialIdAndProvider(oAuthUserInfo.socialId(), Provider.KAKAO).get(); User user = userRepository.findById(socialAccount.getId()).get(); assertAll( diff --git a/src/test/java/com/swyp8team2/auth/application/JwtServiceTest.java b/src/test/java/com/swyp8team2/auth/application/JwtServiceTest.java index a21e7164..bd08fc2f 100644 --- a/src/test/java/com/swyp8team2/auth/application/JwtServiceTest.java +++ b/src/test/java/com/swyp8team2/auth/application/JwtServiceTest.java @@ -6,6 +6,7 @@ import com.swyp8team2.auth.application.jwt.TokenPair; import com.swyp8team2.auth.domain.RefreshToken; import com.swyp8team2.auth.domain.RefreshTokenRepository; +import com.swyp8team2.auth.presentation.dto.TokenResponse; import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; import com.swyp8team2.support.IntegrationTest; @@ -39,9 +40,10 @@ void createToken() throws Exception { .willReturn(expectedTokenPair); //when - TokenPair tokenPair = jwtService.createToken(givenUserId); + TokenResponse tokenResponse = jwtService.createToken(givenUserId); //then + TokenPair tokenPair = tokenResponse.tokenPair(); RefreshToken findRefreshToken = refreshTokenRepository.findByUserId(givenUserId).get(); assertThat(tokenPair).isEqualTo(expectedTokenPair); assertThat(findRefreshToken.getToken()).isEqualTo(expectedTokenPair.refreshToken()); @@ -62,9 +64,10 @@ void reissue() throws Exception { refreshTokenRepository.save(new RefreshToken(givenUserId, givenRefreshToken)); //when - TokenPair tokenPair = jwtService.reissue(givenRefreshToken); + TokenResponse tokenResponse = jwtService.reissue(givenRefreshToken); //then + TokenPair tokenPair = tokenResponse.tokenPair(); RefreshToken findRefreshToken = refreshTokenRepository.findByUserId(givenUserId).get(); assertThat(tokenPair).isEqualTo(expectedTokenPair); assertThat(findRefreshToken.getToken()).isEqualTo(newRefreshToken); diff --git a/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java b/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java index 4fb50574..a9a9aa4f 100644 --- a/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java +++ b/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java @@ -4,6 +4,7 @@ import com.swyp8team2.auth.application.jwt.TokenPair; import com.swyp8team2.auth.presentation.dto.GuestTokenResponse; import com.swyp8team2.auth.presentation.dto.OAuthSignInRequest; +import com.swyp8team2.auth.presentation.dto.AuthResponse; import com.swyp8team2.auth.presentation.dto.TokenResponse; import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; @@ -41,9 +42,9 @@ class AuthControllerTest extends RestDocsTest { void kakaoOAuthSignIn() throws Exception { //given TokenPair expectedTokenPair = new TokenPair("accessToken", "refreshToken"); - TokenResponse response = new TokenResponse(expectedTokenPair.accessToken()); + AuthResponse response = new AuthResponse(expectedTokenPair.accessToken(), 1L); given(authService.oauthSignIn(anyString(), anyString())) - .willReturn(expectedTokenPair); + .willReturn(new TokenResponse(expectedTokenPair, 1L)); OAuthSignInRequest request = new OAuthSignInRequest("code", "https://dev.photopic.site"); //when then @@ -64,7 +65,8 @@ void kakaoOAuthSignIn() throws Exception { fieldWithPath("redirectUri").description("카카오 인증 redirect uri") ), responseFields( - fieldWithPath("accessToken").description("액세스 토큰") + fieldWithPath("accessToken").description("액세스 토큰"), + fieldWithPath("userId").description("유저 Id") ), responseCookies( cookieWithName(CustomHeader.CustomCookie.REFRESH_TOKEN).description("리프레시 토큰") @@ -78,9 +80,10 @@ void kakaoOAuthSignIn() throws Exception { void reissue() throws Exception { //given String newRefreshToken = "newRefreshToken"; + TokenPair tokenPair = new TokenPair("accessToken", newRefreshToken); given(authService.reissue(anyString())) - .willReturn(new TokenPair("accessToken", newRefreshToken)); - TokenResponse response = new TokenResponse("accessToken"); + .willReturn(new TokenResponse(tokenPair, 1L)); + AuthResponse response = new AuthResponse(tokenPair.accessToken(), 1L); //when then mockMvc.perform(post("/auth/reissue") @@ -101,7 +104,8 @@ void reissue() throws Exception { cookieWithName(CustomHeader.CustomCookie.REFRESH_TOKEN).description("새 리프레시 토큰") ), responseFields( - fieldWithPath("accessToken").description("새 액세스 토큰") + fieldWithPath("accessToken").description("새 액세스 토큰"), + fieldWithPath("userId").description("유저 Id") ) )); } From 48c0c8873d09ae02e7f4888c2d49cbc8f754ad40 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Fri, 28 Feb 2025 16:13:34 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EB=B3=B8=EC=9D=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/presentation/UserController.java | 9 ++++++ .../user/presentation/UserControllerTest.java | 29 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/swyp8team2/user/presentation/UserController.java b/src/main/java/com/swyp8team2/user/presentation/UserController.java index dc5ac165..332679ed 100644 --- a/src/main/java/com/swyp8team2/user/presentation/UserController.java +++ b/src/main/java/com/swyp8team2/user/presentation/UserController.java @@ -1,9 +1,11 @@ package com.swyp8team2.user.presentation; +import com.swyp8team2.auth.domain.UserInfo; import com.swyp8team2.user.application.UserService; import com.swyp8team2.user.presentation.dto.UserInfoResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -20,4 +22,11 @@ public class UserController { public ResponseEntity findUserInfo(@PathVariable("userId") Long userId) { return ResponseEntity.ok(userService.findById(userId)); } + + @GetMapping("/me") + public ResponseEntity findMyInfo( + @AuthenticationPrincipal UserInfo userInfo + ) { + return ResponseEntity.ok(userService.findById(userInfo.userId())); + } } diff --git a/src/test/java/com/swyp8team2/user/presentation/UserControllerTest.java b/src/test/java/com/swyp8team2/user/presentation/UserControllerTest.java index f11a7990..8490a66a 100644 --- a/src/test/java/com/swyp8team2/user/presentation/UserControllerTest.java +++ b/src/test/java/com/swyp8team2/user/presentation/UserControllerTest.java @@ -1,13 +1,16 @@ package com.swyp8team2.user.presentation; import com.swyp8team2.support.RestDocsTest; +import com.swyp8team2.support.WithMockUserInfo; import com.swyp8team2.user.presentation.dto.UserInfoResponse; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.security.test.context.support.WithMockUser; import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; import static org.springframework.restdocs.payload.JsonFieldType.STRING; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; @@ -20,7 +23,7 @@ class UserControllerTest extends RestDocsTest { @Test - @WithMockUser + @WithMockUserInfo @DisplayName("유저 정보 조회") void findUserInfo() throws Exception { //given @@ -43,4 +46,28 @@ void findUserInfo() throws Exception { ) )); } + + @Test + @WithMockUserInfo + @DisplayName("본인 정보 조회") + void findMe() throws Exception { + //given + UserInfoResponse response = new UserInfoResponse(1L, "nickname", "https://image.com/profile-image"); + given(userService.findById(1L)) + .willReturn(response); + + //when then + mockMvc.perform(RestDocumentationRequestBuilders.get("/users/me") + .header(HttpHeaders.AUTHORIZATION, "Bearer access-token")) + .andExpect(status().isOk()) + .andExpect(content().json(objectMapper.writeValueAsString(response))) + .andDo(restDocs.document( + requestHeaders(authorizationHeader()), + responseFields( + fieldWithPath("id").description("유저 아이디").type(NUMBER), + fieldWithPath("nickname").description("닉네임").type(STRING), + fieldWithPath("profileUrl").description("프로필 이미지 URL").type(STRING) + ) + )); + } } From 18e5e0eeaa174ef8cab44fd046534bac4b125ed4 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Fri, 28 Feb 2025 16:17:21 +0900 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20=EC=9C=A0=EC=A0=80=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/users.adoc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/docs/asciidoc/users.adoc b/src/docs/asciidoc/users.adoc index 9faf6982..ae247c22 100644 --- a/src/docs/asciidoc/users.adoc +++ b/src/docs/asciidoc/users.adoc @@ -4,4 +4,9 @@ [[유저-정보-조회]] === `GET` 유저 정보 조회 -operation::user-controller-test/find-user-info[snippets='http-request,curl-request,path-parameters,http-response,response-fields'] \ No newline at end of file +operation::user-controller-test/find-user-info[snippets='http-request,curl-request,path-parameters,http-response,response-fields'] + +[[본인-정보-조회]] +=== `GET` 본인 정보 조회 + +operation::user-controller-test/find-me[snippets='http-request,curl-request,request-headers,http-response,response-fields']