From 8cd298c8da929d6884fa25cadd1197c7cde29736 Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:09:44 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20api?= =?UTF-8?q?=20controller=20=EA=B5=AC=ED=98=84=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doorip/user/api/UserApiController.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 doorip-api/src/main/java/org/doorip/user/api/UserApiController.java diff --git a/doorip-api/src/main/java/org/doorip/user/api/UserApiController.java b/doorip-api/src/main/java/org/doorip/user/api/UserApiController.java new file mode 100644 index 0000000..a1dc5c4 --- /dev/null +++ b/doorip-api/src/main/java/org/doorip/user/api/UserApiController.java @@ -0,0 +1,25 @@ +package org.doorip.user.api; + +import lombok.RequiredArgsConstructor; +import org.doorip.common.ApiResponse; +import org.doorip.common.ApiResponseUtil; +import org.doorip.message.SuccessMessage; +import org.doorip.user.dto.request.UserSignInRequest; +import org.doorip.user.dto.response.UserResponse; +import org.doorip.user.service.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RequiredArgsConstructor +@RequestMapping("/api/users") +@RestController +public class UserApiController { + private final UserService userService; + + @PostMapping("/signin") + public ResponseEntity> signIn(@RequestHeader("Authorization") final String token, + @RequestParam final UserSignInRequest request) { + final UserResponse response = userService.signIn(token, request); + return ApiResponseUtil.success(SuccessMessage.OK, response); + } +} From 007054e3d547aca9ce5414a4c1caf1c192b2c48c Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:10:36 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20ser?= =?UTF-8?q?vice=20=EA=B5=AC=ED=98=84=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/user/service/UserService.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 doorip-api/src/main/java/org/doorip/user/service/UserService.java diff --git a/doorip-api/src/main/java/org/doorip/user/service/UserService.java b/doorip-api/src/main/java/org/doorip/user/service/UserService.java new file mode 100644 index 0000000..bfbb776 --- /dev/null +++ b/doorip-api/src/main/java/org/doorip/user/service/UserService.java @@ -0,0 +1,59 @@ +package org.doorip.user.service; + +import lombok.RequiredArgsConstructor; +import org.doorip.auth.jwt.JwtProvider; +import org.doorip.auth.jwt.Token; +import org.doorip.exception.EntityNotFoundException; +import org.doorip.message.ErrorMessage; +import org.doorip.openfeign.apple.AppleOAuthProvider; +import org.doorip.openfeign.kakao.KakaoOAuthProvider; +import org.doorip.user.domain.Platform; +import org.doorip.user.domain.RefreshToken; +import org.doorip.user.domain.User; +import org.doorip.user.dto.request.UserSignInRequest; +import org.doorip.user.dto.response.UserResponse; +import org.doorip.user.repository.RefreshTokenRepository; +import org.doorip.user.repository.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import static org.doorip.user.domain.Platform.APPLE; +import static org.doorip.user.domain.Platform.getEnumPlatformFromStringPlatform; + +@RequiredArgsConstructor +@Service +@Transactional(readOnly = true) +public class UserService { + private final UserRepository userRepository; + private final RefreshTokenRepository refreshTokenRepository; + private final JwtProvider jwtProvider; + private final AppleOAuthProvider appleOAuthProvider; + private final KakaoOAuthProvider kakaoOAuthProvider; + + public UserResponse signIn(String token, UserSignInRequest request) { + Platform enumPlatform = getEnumPlatformFromStringPlatform(request.platform()); + String platformId = getPlatformId(token, enumPlatform); + User findUser = getUser(enumPlatform, platformId); + Token issueToken = jwtProvider.issueToken(findUser.getId()); + updateRefreshToken(issueToken.refreshToken(), findUser); + + return UserResponse.of(issueToken); + } + + private String getPlatformId(String token, Platform platform) { + if (platform == APPLE) { + return appleOAuthProvider.getApplePlatformId(token); + } + return kakaoOAuthProvider.getKakaoPlatformId(token); + } + + private User getUser(Platform platform, String platformId) { + return userRepository.findUserByPlatformAndPlatformId(platform, platformId) + .orElseThrow(() -> new EntityNotFoundException(ErrorMessage.USER_NOT_FOUND)); + } + + private void updateRefreshToken(String refreshToken, User user) { + user.updateRefreshToken(refreshToken); + refreshTokenRepository.save(RefreshToken.createRefreshToken(user.getId(), refreshToken)); + } +} From 17ad9d8f97a4cf233819d89511735302d563257a Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:11:09 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20user=20repository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/user/repository/UserRepository.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 doorip-domain/src/main/java/org/doorip/user/repository/UserRepository.java diff --git a/doorip-domain/src/main/java/org/doorip/user/repository/UserRepository.java b/doorip-domain/src/main/java/org/doorip/user/repository/UserRepository.java new file mode 100644 index 0000000..539531e --- /dev/null +++ b/doorip-domain/src/main/java/org/doorip/user/repository/UserRepository.java @@ -0,0 +1,11 @@ +package org.doorip.user.repository; + +import org.doorip.user.domain.Platform; +import org.doorip.user.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + Optional findUserByPlatformAndPlatformId(Platform platform, String platformId); +} From 2274d28bc04d14c62abe460258da0731e4bab880 Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:11:44 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20use?= =?UTF-8?q?r=20dto=20=EA=B5=AC=ED=98=84=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/dto/request/UserSignInRequest.java | 6 ++++++ .../doorip/user/dto/response/UserResponse.java | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 doorip-api/src/main/java/org/doorip/user/dto/request/UserSignInRequest.java create mode 100644 doorip-api/src/main/java/org/doorip/user/dto/response/UserResponse.java diff --git a/doorip-api/src/main/java/org/doorip/user/dto/request/UserSignInRequest.java b/doorip-api/src/main/java/org/doorip/user/dto/request/UserSignInRequest.java new file mode 100644 index 0000000..8a36def --- /dev/null +++ b/doorip-api/src/main/java/org/doorip/user/dto/request/UserSignInRequest.java @@ -0,0 +1,6 @@ +package org.doorip.user.dto.request; + +public record UserSignInRequest( + String platform +) { +} diff --git a/doorip-api/src/main/java/org/doorip/user/dto/response/UserResponse.java b/doorip-api/src/main/java/org/doorip/user/dto/response/UserResponse.java new file mode 100644 index 0000000..9677b69 --- /dev/null +++ b/doorip-api/src/main/java/org/doorip/user/dto/response/UserResponse.java @@ -0,0 +1,16 @@ +package org.doorip.user.dto.response; + +import org.doorip.auth.jwt.Token; + +public record UserResponse( + String accessToken, + String refreshToken +) { + + public static UserResponse of(Token token) { + return new UserResponse( + token.accessToken(), + token.refreshToken() + ); + } +} From e055027cb51d329a1768196eb6958a77c7b2c7fa Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:12:10 +0900 Subject: [PATCH 05/11] =?UTF-8?q?chore:=20redis=20=EC=84=A4=EC=A0=95=20(#1?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doorip-domain/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/doorip-domain/build.gradle b/doorip-domain/build.gradle index 93144c9..f73e9f0 100644 --- a/doorip-domain/build.gradle +++ b/doorip-domain/build.gradle @@ -1,5 +1,6 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' implementation project(path: ':doorip-common') From b7e554a3906363963e88920c20445efe9a95a7ef Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:12:33 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20refresh=20token=20redis=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/user/domain/RefreshToken.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 doorip-domain/src/main/java/org/doorip/user/domain/RefreshToken.java diff --git a/doorip-domain/src/main/java/org/doorip/user/domain/RefreshToken.java b/doorip-domain/src/main/java/org/doorip/user/domain/RefreshToken.java new file mode 100644 index 0000000..0c78345 --- /dev/null +++ b/doorip-domain/src/main/java/org/doorip/user/domain/RefreshToken.java @@ -0,0 +1,25 @@ +package org.doorip.user.domain; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; + +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Builder(access = AccessLevel.PRIVATE) +@Getter +@RedisHash(value = "refreshToken", timeToLive = 604800000) +public class RefreshToken { + @Id + private Long id; + private String refreshToken; + + public static RefreshToken createRefreshToken(Long userId, String refreshToken) { + return RefreshToken.builder() + .id(userId) + .refreshToken(refreshToken) + .build(); + } +} \ No newline at end of file From 96b80f10c69279ca2b726f01ccf23d4cd1f0f2ae Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:12:59 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20refresh=20token=20repository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doorip/user/repository/RefreshTokenRepository.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doorip-domain/src/main/java/org/doorip/user/repository/RefreshTokenRepository.java diff --git a/doorip-domain/src/main/java/org/doorip/user/repository/RefreshTokenRepository.java b/doorip-domain/src/main/java/org/doorip/user/repository/RefreshTokenRepository.java new file mode 100644 index 0000000..ce9e23f --- /dev/null +++ b/doorip-domain/src/main/java/org/doorip/user/repository/RefreshTokenRepository.java @@ -0,0 +1,7 @@ +package org.doorip.user.repository; + +import org.doorip.user.domain.RefreshToken; +import org.springframework.data.repository.CrudRepository; + +public interface RefreshTokenRepository extends CrudRepository { +} From a11cecb4507b1a665c758f5081c9f521cff30cd5 Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:13:24 +0900 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20enum=20platform=EA=B3=BC=20string?= =?UTF-8?q?=20platform=20=EB=A7=A4=ED=95=91=20=EA=B8=B0=EB=8A=A5=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doorip/user/domain/Platform.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/doorip-domain/src/main/java/org/doorip/user/domain/Platform.java b/doorip-domain/src/main/java/org/doorip/user/domain/Platform.java index c46c049..d3a7fd6 100644 --- a/doorip-domain/src/main/java/org/doorip/user/domain/Platform.java +++ b/doorip-domain/src/main/java/org/doorip/user/domain/Platform.java @@ -1,5 +1,23 @@ package org.doorip.user.domain; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.doorip.exception.InvalidValueException; +import org.doorip.message.ErrorMessage; + +import java.util.Arrays; + +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) public enum Platform { - KAKAO, APPLE -} + APPLE("apple"), + KAKAO("kakao"); + + private final String stringPlatform; + + public static Platform getEnumPlatformFromStringPlatform(String stringPlatform) { + return Arrays.stream(values()) + .filter(platform -> platform.stringPlatform.equals(stringPlatform)) + .findFirst() + .orElseThrow(() -> new InvalidValueException(ErrorMessage.INVALID_PLATFORM_TYPE)); + } +} \ No newline at end of file From d4a5d9a496bc8bc941c18367ad2f58490392ad90 Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:13:53 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20user=20refresh=20token=20update?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doorip-domain/src/main/java/org/doorip/user/domain/User.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doorip-domain/src/main/java/org/doorip/user/domain/User.java b/doorip-domain/src/main/java/org/doorip/user/domain/User.java index abd5ea8..7f994e2 100644 --- a/doorip-domain/src/main/java/org/doorip/user/domain/User.java +++ b/doorip-domain/src/main/java/org/doorip/user/domain/User.java @@ -33,4 +33,8 @@ public class User extends BaseTimeEntity { @Builder.Default @OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE) private List participants = new ArrayList<>(); + + public void updateRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } } From 8bd323e953c8b408b00e304ac07bc0c099a800b2 Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:14:16 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/doorip/message/ErrorMessage.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doorip-common/src/main/java/org/doorip/message/ErrorMessage.java b/doorip-common/src/main/java/org/doorip/message/ErrorMessage.java index 8de3cef..9391bdb 100644 --- a/doorip-common/src/main/java/org/doorip/message/ErrorMessage.java +++ b/doorip-common/src/main/java/org/doorip/message/ErrorMessage.java @@ -12,6 +12,7 @@ public enum ErrorMessage { * 400 Bad Request */ BAD_REQUEST(HttpStatus.BAD_REQUEST, "e4000", "잘못된 요청입니다."), + INVALID_PLATFORM_TYPE(HttpStatus.BAD_REQUEST, "e4001", "유효하지 않은 플랫폼 타입입니다."), /** * 401 Unauthorized @@ -40,6 +41,7 @@ public enum ErrorMessage { * 404 Not Found */ ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "e4040", "대상을 찾을 수 없습니다."), + USER_NOT_FOUND(HttpStatus.NOT_FOUND, "e4041", "존재하지 않는 회원입니다."), /** * 405 Method Not Allowed From 0d56621a5149f01721d63d3dfb2c60662d054ac0 Mon Sep 17 00:00:00 2001 From: gardening-y <60008786@naver.com> Date: Sun, 7 Jan 2024 18:49:38 +0900 Subject: [PATCH 11/11] =?UTF-8?q?fix:=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/doorip/user/api/UserApiController.java | 3 ++- .../src/main/java/org/doorip/user/service/UserService.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doorip-api/src/main/java/org/doorip/user/api/UserApiController.java b/doorip-api/src/main/java/org/doorip/user/api/UserApiController.java index a1dc5c4..4350456 100644 --- a/doorip-api/src/main/java/org/doorip/user/api/UserApiController.java +++ b/doorip-api/src/main/java/org/doorip/user/api/UserApiController.java @@ -8,11 +8,12 @@ import org.doorip.user.dto.response.UserResponse; import org.doorip.user.service.UserService; import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @RequiredArgsConstructor @RequestMapping("/api/users") -@RestController +@Controller public class UserApiController { private final UserService userService; diff --git a/doorip-api/src/main/java/org/doorip/user/service/UserService.java b/doorip-api/src/main/java/org/doorip/user/service/UserService.java index bfbb776..1c56712 100644 --- a/doorip-api/src/main/java/org/doorip/user/service/UserService.java +++ b/doorip-api/src/main/java/org/doorip/user/service/UserService.java @@ -30,6 +30,7 @@ public class UserService { private final AppleOAuthProvider appleOAuthProvider; private final KakaoOAuthProvider kakaoOAuthProvider; + @Transactional public UserResponse signIn(String token, UserSignInRequest request) { Platform enumPlatform = getEnumPlatformFromStringPlatform(request.platform()); String platformId = getPlatformId(token, enumPlatform);