From 1ffe225c54e832cfd25315ea8b0c25c39d16047e Mon Sep 17 00:00:00 2001 From: xb205 <62425964+devxb@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:26:10 +0900 Subject: [PATCH] =?UTF-8?q?[refactor]=20:=20login=EB=90=9C=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EC=A1=B0=ED=9A=8C=20api=EA=B0=80=20email=EC=9D=84?= =?UTF-8?q?=20=ED=95=A8=EA=BB=98=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20(#401)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/acceptance/test/UserInitializer.java | 4 ++- .../user/UserAcceptanceTestSupporter.java | 2 +- .../test/user/UserAcceptanceValidator.java | 5 ++-- .../LoginedTargetFindAcceptanceTest.java | 13 +++++++-- .../common/dto/CreateAuthTokenRequest.java | 1 - .../auth/application/common/dto/Payload.java | 1 - .../service/AuthTokenCreateService.java | 3 -- .../service/JwtLoginedDecryptService.java | 7 ++--- .../service/SignInWithOAuthService.java | 2 +- .../service/AuthTokenCreateServiceTest.java | 25 ++-------------- .../service/JwtLoginedDecryptServiceTest.java | 10 +++---- support/e2e/v1_13_get_logined_target.hurl | 29 +++++++++++++++++++ .../application/common/dto/LoginedInfo.java | 21 ++++++++------ .../application/common/dto/TokenInfo.java | 11 +++++++ .../port/in/LoginedUserGetByTokenUseCase.java | 2 +- .../LoginedUserGetByTokenPort.java | 6 ++-- .../port/out/persistence/UserGetPort.java | 8 +++++ .../service/LoginedUserGetByTokenService.java | 12 ++++++-- .../LoginedUserGetByTokenServiceTest.java | 27 +++++++++++++---- .../jpa/adaptor/create/UserGetAdaptor.java | 23 +++++++++++++++ .../logined/LoginedUserGetController.java | 7 ++--- .../logined/response/LoginedInfoResponse.java | 7 +++++ 22 files changed, 154 insertions(+), 72 deletions(-) create mode 100644 support/e2e/v1_13_get_logined_target.hurl create mode 100644 user/user-application/src/main/java/me/nalab/user/application/common/dto/TokenInfo.java create mode 100644 user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/UserGetPort.java create mode 100644 user/user-jpa-adapter/src/main/java/me/nalab/user/jpa/adaptor/create/UserGetAdaptor.java diff --git a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/UserInitializer.java b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/UserInitializer.java index a9f6f77b..34f90d2a 100644 --- a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/UserInitializer.java +++ b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/UserInitializer.java @@ -4,6 +4,7 @@ import me.nalab.core.data.user.UserOAuthInfoEntity; import me.nalab.core.idgenerator.idcore.IdGenerator; import me.nalab.user.domain.user.Provider; +import me.nalab.user.domain.user.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -22,7 +23,7 @@ public class UserInitializer { private IdGenerator idGenerator; @Transactional - public void saveUserWithOAuth(Provider provider, String name, String email, Instant date) { + public Long saveUserWithOAuth(Provider provider, String name, String email, Instant date) { var userEntity = UserEntity.builder() .id(idGenerator.generate()) .nickname(name) @@ -42,6 +43,7 @@ public void saveUserWithOAuth(Provider provider, String name, String email, Inst entityManager.persist(userEntity); entityManager.persist(userOauthInfoEntity); + return userEntity.getId(); } } diff --git a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceTestSupporter.java b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceTestSupporter.java index cf415cb7..0731091e 100644 --- a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceTestSupporter.java +++ b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceTestSupporter.java @@ -17,7 +17,7 @@ public class UserAcceptanceTestSupporter { protected ResultActions getLoginedUser(String token) throws Exception { return mockMvc.perform(MockMvcRequestBuilders - .get(API_VERSION + "/users/logined") + .get(API_VERSION + "/users/logins") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, token) ); diff --git a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceValidator.java b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceValidator.java index bf074b3f..56504b3b 100644 --- a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceValidator.java +++ b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/UserAcceptanceValidator.java @@ -6,11 +6,12 @@ public class UserAcceptanceValidator { - public static void assertIsLogined(ResultActions resultActions, Long targetId, String nickname) throws Exception { + public static void assertIsLogined(ResultActions resultActions, Long targetId, String nickname, String email) throws Exception { resultActions.andExpectAll( status().isOk(), jsonPath("$.target_id").value(targetId), - jsonPath("$.nickname").value(nickname) + jsonPath("$.nickname").value(nickname), + jsonPath("$.email").value(email) ); } diff --git a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/logined/LoginedTargetFindAcceptanceTest.java b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/logined/LoginedTargetFindAcceptanceTest.java index 176f5d65..df70b9ab 100644 --- a/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/logined/LoginedTargetFindAcceptanceTest.java +++ b/api/acceptance-test/src/test/java/me/nalab/luffy/api/acceptance/test/user/logined/LoginedTargetFindAcceptanceTest.java @@ -5,6 +5,8 @@ import java.time.Instant; import java.util.Set; +import me.nalab.luffy.api.acceptance.test.UserInitializer; +import me.nalab.user.domain.user.Provider; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -40,14 +42,19 @@ class LoginedTargetFindAcceptanceTest extends UserAcceptanceTestSupporter { @Autowired private JwtUtils jwtUtils; + @Autowired + private UserInitializer userInitializer; + @Test @DisplayName("로그인된 유저 정보 조회 성공 테스트") void GET_LOGINED_USER_SUCCESS() throws Exception { // given String nickname = "devxb"; + String email = "email"; + Long userId = userInitializer.saveUserWithOAuth(Provider.DEFAULT, nickname, "email", Instant.now()); Long targetId = targetInitializer.saveTargetAndGetId(nickname, Instant.now()); - String token = jwtUtils.createAccessToken(Set.of(new Payload(Payload.Key.NICKNAME, nickname), - new Payload(Payload.Key.USER_ID, 12345 + ""), new Payload(Payload.Key.TARGET_ID, targetId + ""))); + String token = jwtUtils.createAccessToken(Set.of(new Payload(Payload.Key.USER_ID, String.valueOf(userId)), + new Payload(Payload.Key.TARGET_ID, String.valueOf(targetId)))); applicationEventPublisher.publishEvent( MockUserRegisterEvent.builder().expectedToken("bearer " + token).expectedId(targetId).build()); @@ -55,7 +62,7 @@ void GET_LOGINED_USER_SUCCESS() throws Exception { ResultActions resultActions = getLoginedUser("bearer " + token); // then - assertIsLogined(resultActions, targetId, nickname); + assertIsLogined(resultActions, targetId, nickname, email); } } diff --git a/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/CreateAuthTokenRequest.java b/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/CreateAuthTokenRequest.java index 6c98c9d4..16fe250f 100644 --- a/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/CreateAuthTokenRequest.java +++ b/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/CreateAuthTokenRequest.java @@ -5,6 +5,5 @@ @Data public class CreateAuthTokenRequest { private final String userId; - private final String nickname; private final String targetId; } diff --git a/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/Payload.java b/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/Payload.java index f6fff8d9..5f7887a0 100644 --- a/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/Payload.java +++ b/auth/auth-application/src/main/java/me/nalab/auth/application/common/dto/Payload.java @@ -14,6 +14,5 @@ public class Payload { public enum Key { USER_ID, TARGET_ID, - NICKNAME, } } diff --git a/auth/auth-application/src/main/java/me/nalab/auth/application/service/AuthTokenCreateService.java b/auth/auth-application/src/main/java/me/nalab/auth/application/service/AuthTokenCreateService.java index 29c7e6fd..080d85ef 100644 --- a/auth/auth-application/src/main/java/me/nalab/auth/application/service/AuthTokenCreateService.java +++ b/auth/auth-application/src/main/java/me/nalab/auth/application/service/AuthTokenCreateService.java @@ -22,15 +22,12 @@ public class AuthTokenCreateService implements AuthTokenCreateUseCase { @Override public AuthToken create(CreateAuthTokenRequest request) { var userId = request.getUserId(); - var nickname = request.getNickname(); var targetId = request.getTargetId(); Assert.isTrue(userId != null && !userId.isBlank(), "Authentication token 생성 시 유저 식별자는 필수입니다."); - Assert.isTrue(nickname != null && !nickname.isBlank(), "Authentication token 생성 시 유저의 별명은 필수입니다."); Assert.isTrue(targetId != null && !targetId.isBlank(), "Authentication token 생성 시 유저의 별명은 필수입니다."); Set payload = new HashSet<>(); payload.add(new Payload(Payload.Key.USER_ID, userId)); - payload.add(new Payload(Payload.Key.NICKNAME, nickname)); payload.add(new Payload(Payload.Key.TARGET_ID, targetId)); String token = createToken(payload); diff --git a/auth/auth-application/src/main/java/me/nalab/auth/application/service/JwtLoginedDecryptService.java b/auth/auth-application/src/main/java/me/nalab/auth/application/service/JwtLoginedDecryptService.java index 8f79ead5..53ab1be2 100644 --- a/auth/auth-application/src/main/java/me/nalab/auth/application/service/JwtLoginedDecryptService.java +++ b/auth/auth-application/src/main/java/me/nalab/auth/application/service/JwtLoginedDecryptService.java @@ -9,7 +9,7 @@ import me.nalab.auth.application.common.dto.Payload; import me.nalab.auth.application.common.utils.JwtUtils; import me.nalab.auth.application.port.in.web.TargetIdGetPort; -import me.nalab.user.application.common.dto.LoginedInfo; +import me.nalab.user.application.common.dto.TokenInfo; import me.nalab.user.application.port.out.persistence.LoginedUserGetByTokenPort; @Service @@ -19,14 +19,13 @@ public class JwtLoginedDecryptService implements LoginedUserGetByTokenPort, Targ private final JwtUtils jwtUtils; @Override - public LoginedInfo decryptToken(String encryptedToken) { + public TokenInfo decryptToken(String encryptedToken) { Assert.isTrue(encryptedToken != null && !encryptedToken.isBlank(), "encryptedToken 으로 blank나 null 값이 들어올 수 없습니다."); DecodedJWT decodedJWT = jwtUtils.verify(encryptedToken); - String nickName = decodedJWT.getClaim(Payload.Key.NICKNAME.name()).asString(); Long userId = Long.valueOf(decodedJWT.getClaim(Payload.Key.USER_ID.name()).asString()); Long targetId = Long.valueOf(decodedJWT.getClaim(Payload.Key.TARGET_ID.name()).asString()); - return new LoginedInfo(nickName, targetId, userId); + return new TokenInfo(targetId, userId); } @Override diff --git a/auth/auth-application/src/main/java/me/nalab/auth/application/service/SignInWithOAuthService.java b/auth/auth-application/src/main/java/me/nalab/auth/application/service/SignInWithOAuthService.java index 70866829..2e37ff5f 100644 --- a/auth/auth-application/src/main/java/me/nalab/auth/application/service/SignInWithOAuthService.java +++ b/auth/auth-application/src/main/java/me/nalab/auth/application/service/SignInWithOAuthService.java @@ -36,7 +36,7 @@ public AuthToken signInWithOAuth(SignInWithOAuthRequest request) { var userId = foundUser.orElseThrow(IllegalAccessError::new); var targetId = targetFindByUsernameUseCase.findTargetByUsername(request.getUsername()).orElseThrow().getId(); - var authTokenCreateRequest = new CreateAuthTokenRequest(userId.toString(), request.getUsername(), String.valueOf(targetId)); + var authTokenCreateRequest = new CreateAuthTokenRequest(userId.toString(), String.valueOf(targetId)); return authTokenCreateUseCase.create(authTokenCreateRequest); } diff --git a/auth/auth-application/src/test/java/me/nalab/auth/application/service/AuthTokenCreateServiceTest.java b/auth/auth-application/src/test/java/me/nalab/auth/application/service/AuthTokenCreateServiceTest.java index eff30c90..2b1171a8 100644 --- a/auth/auth-application/src/test/java/me/nalab/auth/application/service/AuthTokenCreateServiceTest.java +++ b/auth/auth-application/src/test/java/me/nalab/auth/application/service/AuthTokenCreateServiceTest.java @@ -31,25 +31,8 @@ class AuthTokenCreateServiceTest { @DisplayName("유저식별자가 없거나 비어있다면 예외를 발생시킨다") void THROW_EXCEPTION_WHEN_USER_ID_IS_BLANK(String userId) { // given - var nickname = "nickname"; var targetId = "targetId"; - var request = new CreateAuthTokenRequest(userId, nickname, targetId); - - // when - var throwable = Assertions.catchThrowable(() -> authTokenCreateService.create(request)); - - // then - Assertions.assertThat(throwable).isInstanceOf(IllegalArgumentException.class); - } - - @ParameterizedTest - @NullAndEmptySource() - @DisplayName("닉네임가 없거나 비어있다면 예외를 발생시킨다") - void THROW_EXCEPTION_WHEN_NICKNAME_IS_BLANK(String nickname) { - // given - var userId = "userId"; - var targetId = "targetId"; - var request = new CreateAuthTokenRequest(userId, nickname, targetId); + var request = new CreateAuthTokenRequest(userId, targetId); // when var throwable = Assertions.catchThrowable(() -> authTokenCreateService.create(request)); @@ -64,8 +47,7 @@ void THROW_EXCEPTION_WHEN_NICKNAME_IS_BLANK(String nickname) { void THROW_EXCEPTION_WHEN_TARGET_ID_IS_BLANK(String targetId) { // given var userId = "userId"; - var nickname = "nickname"; - var request = new CreateAuthTokenRequest(userId, nickname, targetId); + var request = new CreateAuthTokenRequest(userId, targetId); // when var throwable = Assertions.catchThrowable(() -> authTokenCreateService.create(request)); @@ -79,9 +61,8 @@ void THROW_EXCEPTION_WHEN_TARGET_ID_IS_BLANK(String targetId) { void RETURN_TOKEN_WHEN_VALID_REQUEST() { // given var userId = "userId"; - var nickname = "nickname"; var targetId = "targetId"; - var request = new CreateAuthTokenRequest(userId, nickname, targetId); + var request = new CreateAuthTokenRequest(userId, targetId); var expectedToken = "token"; when(jwtUtils.createAccessToken(any())).thenReturn(expectedToken); diff --git a/auth/auth-application/src/test/java/me/nalab/auth/application/service/JwtLoginedDecryptServiceTest.java b/auth/auth-application/src/test/java/me/nalab/auth/application/service/JwtLoginedDecryptServiceTest.java index 89674276..9a6f5fdf 100644 --- a/auth/auth-application/src/test/java/me/nalab/auth/application/service/JwtLoginedDecryptServiceTest.java +++ b/auth/auth-application/src/test/java/me/nalab/auth/application/service/JwtLoginedDecryptServiceTest.java @@ -18,7 +18,7 @@ import me.nalab.auth.application.common.dto.Payload; import me.nalab.auth.application.common.property.JwtProperties; import me.nalab.auth.application.common.utils.JwtUtils; -import me.nalab.user.application.common.dto.LoginedInfo; +import me.nalab.user.application.common.dto.TokenInfo; @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {JwtLoginedDecryptService.class, JwtUtils.class, JwtProperties.class}) @@ -38,11 +38,11 @@ void JWT_DECRYPT_SUCCESS() { long userId = 12345; long targetId = 54321; String requestToken = jwtUtils.createAccessToken( - Set.of(new Payload(Payload.Key.NICKNAME, nickName), new Payload(Payload.Key.USER_ID, userId + ""), + Set.of(new Payload(Payload.Key.USER_ID, userId + ""), new Payload(Payload.Key.TARGET_ID, targetId + ""))); // when - LoginedInfo response = jwtLoginedDecryptService.decryptToken(requestToken); + TokenInfo response = jwtLoginedDecryptService.decryptToken(requestToken); // then assertDecryptedInfo(response, nickName, userId, targetId); @@ -59,9 +59,8 @@ void THROW_EXCEPTION_WHEN_TOKEN_IS_NULL_OR_EMPTY(String token) { assertThat(throwable).isInstanceOf(IllegalArgumentException.class); } - private void assertDecryptedInfo(LoginedInfo response, String expectedName, Long expectedUserId, + private void assertDecryptedInfo(TokenInfo response, String expectedName, Long expectedUserId, Long expectedTargetId) { - Assertions.assertEquals(response.getNickName(), expectedName); Assertions.assertEquals(response.getUserId(), expectedUserId); Assertions.assertEquals(response.getTargetId(), expectedTargetId); } @@ -74,7 +73,6 @@ void DECRYPTE_TARGET_ID_SUCCESS() { long userId = 12345; long targetId = 54321; String requestToken = jwtUtils.createAccessToken(Set.of( - new Payload(Payload.Key.NICKNAME, nickName), new Payload(Payload.Key.USER_ID, String.valueOf(userId)), new Payload(Payload.Key.TARGET_ID, String.valueOf(targetId)) )); diff --git a/support/e2e/v1_13_get_logined_target.hurl b/support/e2e/v1_13_get_logined_target.hurl new file mode 100644 index 00000000..8407dce4 --- /dev/null +++ b/support/e2e/v1_13_get_logined_target.hurl @@ -0,0 +1,29 @@ +POST http://nalab-server:8080/v1/oauth/default # Default provider를 통해서 로그인 진행 +{ + "nickname": "devxb", + "email": "get_logined_target@naver.com" +} + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.access_token" exists +jsonpath "$.token_type" exists + +[Captures] +token_type: jsonpath "$.token_type" +auth_token: jsonpath "$.access_token" + +####### + +GET http://nalab-server:8080/v1/users/logins # Token에 해당하는 유저 조회 +Authorization: {{ token_type }} {{ auth_token }} + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.target_id" exists +jsonpath "$.nickname" == "devxb" +jsonpath "$.email" == "get_logined_target@naver.com" diff --git a/user/user-application/src/main/java/me/nalab/user/application/common/dto/LoginedInfo.java b/user/user-application/src/main/java/me/nalab/user/application/common/dto/LoginedInfo.java index c636eec5..2eda3b2d 100644 --- a/user/user-application/src/main/java/me/nalab/user/application/common/dto/LoginedInfo.java +++ b/user/user-application/src/main/java/me/nalab/user/application/common/dto/LoginedInfo.java @@ -1,12 +1,15 @@ package me.nalab.user.application.common.dto; -import lombok.Data; - -@Data -public class LoginedInfo { - - private final String nickName; - private final Long targetId; - private final Long userId; - +import me.nalab.user.domain.user.User; + +public record LoginedInfo( + Long id, + Long targetId, + String nickname, + String email +) { + + public static LoginedInfo from(Long targetId, User user) { + return new LoginedInfo(user.getId(), targetId, user.getNickname(), user.getEmail()); + } } diff --git a/user/user-application/src/main/java/me/nalab/user/application/common/dto/TokenInfo.java b/user/user-application/src/main/java/me/nalab/user/application/common/dto/TokenInfo.java new file mode 100644 index 00000000..4701d5ae --- /dev/null +++ b/user/user-application/src/main/java/me/nalab/user/application/common/dto/TokenInfo.java @@ -0,0 +1,11 @@ +package me.nalab.user.application.common.dto; + +import lombok.Data; + +@Data +public class TokenInfo { + + private final Long targetId; + private final Long userId; + +} diff --git a/user/user-application/src/main/java/me/nalab/user/application/port/in/LoginedUserGetByTokenUseCase.java b/user/user-application/src/main/java/me/nalab/user/application/port/in/LoginedUserGetByTokenUseCase.java index 04f2b722..d70be8b0 100644 --- a/user/user-application/src/main/java/me/nalab/user/application/port/in/LoginedUserGetByTokenUseCase.java +++ b/user/user-application/src/main/java/me/nalab/user/application/port/in/LoginedUserGetByTokenUseCase.java @@ -13,6 +13,6 @@ public interface LoginedUserGetByTokenUseCase { * @param encryptedToken 암호화된 토큰 * @return 복호화된 정보 */ - LoginedInfo decryptToken(String encryptedToken); + LoginedInfo getLoginedInfoByToken(String encryptedToken); } diff --git a/user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/LoginedUserGetByTokenPort.java b/user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/LoginedUserGetByTokenPort.java index 7949f301..00f32f3e 100644 --- a/user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/LoginedUserGetByTokenPort.java +++ b/user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/LoginedUserGetByTokenPort.java @@ -1,6 +1,6 @@ package me.nalab.user.application.port.out.persistence; -import me.nalab.user.application.common.dto.LoginedInfo; +import me.nalab.user.application.common.dto.TokenInfo; /** * token을 받아 decrypt된 유저의 정보를 반환하는 유즈케이스 @@ -8,11 +8,11 @@ public interface LoginedUserGetByTokenPort { /** - * 암호화된 유저의 토큰을 받아, 복호화된 유저의 정보를 반환합니다. + * 암호화된 유저의 토큰을 받아, 복호화된 토큰의 정보를 반환합니다. * * @param encryptedToken 암호화된 토큰 * @return 복호화된 정보 */ - LoginedInfo decryptToken(String encryptedToken); + TokenInfo decryptToken(String encryptedToken); } diff --git a/user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/UserGetPort.java b/user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/UserGetPort.java new file mode 100644 index 00000000..9b6dd4f2 --- /dev/null +++ b/user/user-application/src/main/java/me/nalab/user/application/port/out/persistence/UserGetPort.java @@ -0,0 +1,8 @@ +package me.nalab.user.application.port.out.persistence; + +import me.nalab.user.domain.user.User; + +public interface UserGetPort { + + User getById(Long id); +} diff --git a/user/user-application/src/main/java/me/nalab/user/application/service/LoginedUserGetByTokenService.java b/user/user-application/src/main/java/me/nalab/user/application/service/LoginedUserGetByTokenService.java index d26f94eb..34fa2e4e 100644 --- a/user/user-application/src/main/java/me/nalab/user/application/service/LoginedUserGetByTokenService.java +++ b/user/user-application/src/main/java/me/nalab/user/application/service/LoginedUserGetByTokenService.java @@ -2,26 +2,32 @@ import java.util.Objects; +import me.nalab.user.application.common.dto.LoginedInfo; +import me.nalab.user.application.port.out.persistence.UserGetPort; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; -import me.nalab.user.application.common.dto.LoginedInfo; import me.nalab.user.application.exception.InvalidTokenException; import me.nalab.user.application.port.in.LoginedUserGetByTokenUseCase; import me.nalab.user.application.port.out.persistence.LoginedUserGetByTokenPort; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor public class LoginedUserGetByTokenService implements LoginedUserGetByTokenUseCase { private final LoginedUserGetByTokenPort loginedUserGetByTokenPort; + private final UserGetPort userGetPort; @Override - public LoginedInfo decryptToken(String encryptedToken) { + @Transactional(readOnly = true) + public LoginedInfo getLoginedInfoByToken(String encryptedToken) { Objects.requireNonNull(encryptedToken, "encryptedToken은 null이 되면 안됩니다."); String[] split = encryptedToken.split(" "); throwIfInvalidToken(split); - return loginedUserGetByTokenPort.decryptToken(split[1]); + var tokenInfo = loginedUserGetByTokenPort.decryptToken(split[1]); + var user = userGetPort.getById(tokenInfo.getUserId()); + return LoginedInfo.from(tokenInfo.getTargetId(), user); } private void throwIfInvalidToken(String[] split) { diff --git a/user/user-application/src/test/java/me/nalab/user/application/service/LoginedUserGetByTokenServiceTest.java b/user/user-application/src/test/java/me/nalab/user/application/service/LoginedUserGetByTokenServiceTest.java index 35423160..355e0464 100644 --- a/user/user-application/src/test/java/me/nalab/user/application/service/LoginedUserGetByTokenServiceTest.java +++ b/user/user-application/src/test/java/me/nalab/user/application/service/LoginedUserGetByTokenServiceTest.java @@ -1,18 +1,22 @@ package me.nalab.user.application.service; +import me.nalab.user.application.common.dto.LoginedInfo; +import me.nalab.user.application.port.out.persistence.UserGetPort; +import me.nalab.user.domain.user.User; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; +import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import me.nalab.user.application.common.dto.LoginedInfo; +import me.nalab.user.application.common.dto.TokenInfo; import me.nalab.user.application.exception.InvalidTokenException; import me.nalab.user.application.port.in.LoginedUserGetByTokenUseCase; import me.nalab.user.application.port.out.persistence.LoginedUserGetByTokenPort; @@ -21,23 +25,34 @@ @ContextConfiguration(classes = {LoginedUserGetByTokenService.class}) class LoginedUserGetByTokenServiceTest { + private static final User DEFAULT_USER = User.builder() + .id(54321L) + .email("email") + .nickname("hello") + .build(); + @Autowired private LoginedUserGetByTokenUseCase loginedUserGetByTokenUseCase; @MockBean private LoginedUserGetByTokenPort loginedUserGetByTokenPort; + @MockBean + private UserGetPort userGetPort; + @Test @DisplayName("토큰을 이용해 로그인된 유저의 정보를 조회 성공 테스트") void GET_LOGINED_INFO_BY_TOKEN_SUCCESS() { // given - LoginedInfo expected = new LoginedInfo("hello", 12345L, 54321L); + LoginedInfo expected = new LoginedInfo(DEFAULT_USER.getId(), 12345L, DEFAULT_USER.getNickname(), DEFAULT_USER.getEmail()); + TokenInfo tokenInfo = new TokenInfo(12345L, DEFAULT_USER.getId()); String token = "hello token"; - Mockito.when(loginedUserGetByTokenPort.decryptToken(token.split(" ")[1])).thenReturn(expected); + Mockito.when(loginedUserGetByTokenPort.decryptToken(token.split(" ")[1])).thenReturn(tokenInfo); + Mockito.when(userGetPort.getById(54321L)).thenReturn(DEFAULT_USER); // when - LoginedInfo result = loginedUserGetByTokenUseCase.decryptToken(token); + LoginedInfo result = loginedUserGetByTokenUseCase.getLoginedInfoByToken(token); // then Assertions.assertThat(result).isEqualTo(expected); @@ -47,7 +62,7 @@ void GET_LOGINED_INFO_BY_TOKEN_SUCCESS() { @NullSource void NULL_PARAMETER_TEST(String token) { // when - Throwable result = Assertions.catchThrowable(() -> loginedUserGetByTokenUseCase.decryptToken(token)); + Throwable result = Assertions.catchThrowable(() -> loginedUserGetByTokenUseCase.getLoginedInfoByToken(token)); // then Assertions.assertThat(result).isInstanceOf(NullPointerException.class); @@ -60,7 +75,7 @@ void DECRYPT_INVALID_TOKEN() { String token = "invalid"; // when - Throwable result = Assertions.catchThrowable(() -> loginedUserGetByTokenUseCase.decryptToken(token)); + Throwable result = Assertions.catchThrowable(() -> loginedUserGetByTokenUseCase.getLoginedInfoByToken(token)); // then Assertions.assertThat(result).isInstanceOf(InvalidTokenException.class); diff --git a/user/user-jpa-adapter/src/main/java/me/nalab/user/jpa/adaptor/create/UserGetAdaptor.java b/user/user-jpa-adapter/src/main/java/me/nalab/user/jpa/adaptor/create/UserGetAdaptor.java new file mode 100644 index 00000000..66b51a68 --- /dev/null +++ b/user/user-jpa-adapter/src/main/java/me/nalab/user/jpa/adaptor/create/UserGetAdaptor.java @@ -0,0 +1,23 @@ +package me.nalab.user.jpa.adaptor.create; + +import lombok.RequiredArgsConstructor; +import me.nalab.user.application.port.out.persistence.UserGetPort; +import me.nalab.user.domain.user.User; +import me.nalab.user.jpa.adaptor.create.common.mapper.UserObjectMapper; +import me.nalab.user.jpa.adaptor.create.repository.UserJpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class UserGetAdaptor implements UserGetPort { + + private final UserJpaRepository userJpaRepository; + + @Override + public User getById(Long id) { + var user = userJpaRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException(String.format("Cannot find exists user \"%d\"", id))); + + return UserObjectMapper.toDomain(user); + } +} diff --git a/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/LoginedUserGetController.java b/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/LoginedUserGetController.java index 31b9dbfe..3cad0e7e 100644 --- a/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/LoginedUserGetController.java +++ b/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/LoginedUserGetController.java @@ -7,7 +7,6 @@ import org.springframework.web.bind.annotation.RestController; import lombok.RequiredArgsConstructor; -import me.nalab.user.application.common.dto.LoginedInfo; import me.nalab.user.application.port.in.LoginedUserGetByTokenUseCase; import me.nalab.user.web.adaptor.logined.response.LoginedInfoResponse; @@ -18,11 +17,9 @@ public class LoginedUserGetController { private final LoginedUserGetByTokenUseCase loginedUserGetByTokenUseCase; - @GetMapping("/users/logined") + @GetMapping("/users/logins") public LoginedInfoResponse getLoginedUserByToken(@RequestHeader(HttpHeaders.AUTHORIZATION) String token) { - LoginedInfo loginedInfo = loginedUserGetByTokenUseCase.decryptToken(token); - - return new LoginedInfoResponse(String.valueOf(loginedInfo.getTargetId()), loginedInfo.getNickName()); + return LoginedInfoResponse.of(loginedUserGetByTokenUseCase.getLoginedInfoByToken(token)); } } diff --git a/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/response/LoginedInfoResponse.java b/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/response/LoginedInfoResponse.java index 7197cc1b..a9cfe5b2 100644 --- a/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/response/LoginedInfoResponse.java +++ b/user/user-web-adaptor/src/main/java/me/nalab/user/web/adaptor/logined/response/LoginedInfoResponse.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import me.nalab.user.application.common.dto.LoginedInfo; @Data public class LoginedInfoResponse { @@ -11,5 +12,11 @@ public class LoginedInfoResponse { private final String targetId; @JsonProperty("nickname") private final String nickName; + @JsonProperty("email") + private final String email; + + public static LoginedInfoResponse of(LoginedInfo loginedInfo) { + return new LoginedInfoResponse(String.valueOf(loginedInfo.targetId()), loginedInfo.nickname(), loginedInfo.email()); + } }