diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/business/AuthBusiness.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/business/AuthBusiness.java index 949eb3c..7f6bd5f 100644 --- a/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/business/AuthBusiness.java +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/business/AuthBusiness.java @@ -2,9 +2,12 @@ import com.nerd.favorite18.core.api._common.annotation.Business; import com.nerd.favorite18.core.api._common.client.OAuth2Client; +import com.nerd.favorite18.core.api._common.support.error.CoreApiException; +import com.nerd.favorite18.core.api._common.support.error.ErrorType; import com.nerd.favorite18.core.api._common.utils.SHA256HashUtils; import com.nerd.favorite18.core.api.auth.dto.request.AuthLoginGoogleRequest; import com.nerd.favorite18.core.api.auth.dto.request.AuthRefreshRequest; +import com.nerd.favorite18.core.api.auth.dto.request.AuthSignupGoogleRequest; import com.nerd.favorite18.core.api.auth.dto.response.AuthGoogleAccessTokenResponse; import com.nerd.favorite18.core.api.auth.model.GoogleUserInfo; import com.nerd.favorite18.core.api.auth.model.GoogleUserInfoMobile; @@ -29,14 +32,52 @@ public class AuthBusiness { private final OAuth2Client oauth2Client; /** - * [ 로그인 요청 ] + * [ 회원가입 ] *
- * 1. 구글 OAuth2.0 로그인 요청 클라이언트 실행
+ * 1. OAuth2.0 로그인 진행 후 리다이렉트 되어 실행되는 로직
* - * @return Redirect URI + * @param request 생년월일, 성별, 사용자 정보 + * @return 사용자 정보 */ - public URI login() { - return oauth2Client.getAuthorizationUri(); + public UserDto signUp(AuthSignupGoogleRequest request) { + GoogleUserInfoMobile googleUserInfo = new GoogleUserInfoMobile(request.getUserInfo()); + + return userService.saveUser( + UserRegisterRequest.of( + googleUserInfo.getSubId(), + googleUserInfo.getEmail(), + googleUserInfo.getName(), + request.getBirth(), + request.getGender(), + googleUserInfo.getThumbnail() + ) + ); + } + + /** + * [ 로그인 체크 With Error ] + *
+ * 1. 구글 유저정보 기반으로 DB 에서 유저 조회
+ * 2. 유저 없으면 400 에러 반환
+ * 3. 유저 있으면 바로 유저 조회 결과 반환
+ * 4. 반환된 유저정보 기준으로 Jwt 토큰 발행
+ * + * @param userInfo OAuth 유저정보 + * @return JwtResponse JWT 토큰 발행 + */ + private JwtResponse checkLoginUserWithError(OAuth2UserInfo userInfo) { + UserDto userDto; + try { + // 유저 조회하고 있으면 바로 반환, 만약 유저 상태가 ACTIVE 가 아니면 ACTIVE 로 바꾸고 사용자 반환 + userDto = userService.getUserAndUpdateStatusWithThrow(userInfo.getSubId(), userInfo.getEmail()); + } catch (RuntimeException e) { + throw new CoreApiException(ErrorType.USER_NOT_FOUND, "회원가입이 되어있지 않습니다."); + } + + final JwtResponse jwtResponse = jwtBusiness.issueToken(userDto); + userService.updateUserRefreshToken(userDto.getId(), SHA256HashUtils.hashToken(jwtResponse.getRefreshToken())); + + return jwtResponse; } /** @@ -50,27 +91,18 @@ public URI login() { public JwtResponse loginGoogle(AuthLoginGoogleRequest request) { GoogleUserInfoMobile googleUserInfo = new GoogleUserInfoMobile(request.getUserInfo()); - return checkLoginUser(googleUserInfo); + return checkLoginUserWithError(googleUserInfo); } /** - * [ 웹 콜백 로그인 ] + * [ 로그인 요청 ] *
- * 1. OAuth2.0 로그인 진행 후 리다이렉트 되어 실행되는 로직
- * 2. 구글 API 에서 AccessToken 받음
- * 3. 전달받은 AccessToken 으로 유저정보 API 실행
- * 4. 유저정보로 유저 체크 후 JWT 토큰 발행
+ * 1. 구글 OAuth2.0 로그인 요청 클라이언트 실행
* - * @param authorizationCode 구글로 부터 전달받은 인증코드 - * @return JwtResponse JWT 토큰 발행 + * @return Redirect URI */ - public JwtResponse callbackGoogle(String authorizationCode) { - AuthGoogleAccessTokenResponse tokenResponse = oauth2Client.getAccessToken(authorizationCode); - - String accessToken = tokenResponse.getAccessToken(); - GoogleUserInfo googleUserInfo = new GoogleUserInfo(oauth2Client.getUserInfo(accessToken)); - - return checkLoginUser(googleUserInfo); + public URI login() { + return oauth2Client.getAuthorizationUri(); } /** @@ -92,7 +124,12 @@ private JwtResponse checkLoginUser(OAuth2UserInfo userInfo) { } catch (RuntimeException e) { // 조회되지 않으면 강제 회원가입 후 유저 반환 userDto = userService.saveUser(UserRegisterRequest.of( - userInfo.getSubId(), userInfo.getEmail(), userInfo.getName(), userInfo.getThumbnail()) + userInfo.getSubId(), + userInfo.getEmail(), + userInfo.getName(), + null, + null, + userInfo.getThumbnail()) ); } @@ -102,6 +139,26 @@ private JwtResponse checkLoginUser(OAuth2UserInfo userInfo) { return jwtResponse; } + /** + * [ 웹 콜백 로그인 ] + *
+ * 1. OAuth2.0 로그인 진행 후 리다이렉트 되어 실행되는 로직
+ * 2. 구글 API 에서 AccessToken 받음
+ * 3. 전달받은 AccessToken 으로 유저정보 API 실행
+ * 4. 유저정보로 유저 체크 후 JWT 토큰 발행
+ * + * @param authorizationCode 구글로 부터 전달받은 인증코드 + * @return JwtResponse JWT 토큰 발행 + */ + public JwtResponse callbackGoogle(String authorizationCode) { + AuthGoogleAccessTokenResponse tokenResponse = oauth2Client.getAccessToken(authorizationCode); + + String accessToken = tokenResponse.getAccessToken(); + GoogleUserInfo googleUserInfo = new GoogleUserInfo(oauth2Client.getUserInfo(accessToken)); + + return checkLoginUser(googleUserInfo); + } + /** * [ 리프레쉬 토큰 발행 ] *
diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/controller/AuthOpenApiController.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/controller/AuthOpenApiController.java index d7e4a89..953329c 100644 --- a/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/controller/AuthOpenApiController.java +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/controller/AuthOpenApiController.java @@ -1,9 +1,11 @@ package com.nerd.favorite18.core.api.auth.controller; +import com.nerd.favorite18.core.api._common.support.response.ApiResponse; import com.nerd.favorite18.core.api.auth.business.AuthBusiness; import com.nerd.favorite18.core.api.auth.dto.request.AuthLoginGoogleRequest; +import com.nerd.favorite18.core.api.auth.dto.request.AuthSignupGoogleRequest; import com.nerd.favorite18.core.api.jwt.dto.JwtResponse; -import com.nerd.favorite18.core.api._common.support.response.ApiResponse; +import com.nerd.favorite18.core.api.user.dto.UserDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; @@ -22,11 +24,12 @@ public class AuthOpenApiController { private final AuthBusiness authBusiness; - // 로그인 url 발행 요청 - @GetMapping("/login") - public URI login() { + // 모바일 회원가입 진행 + @PostMapping("/signup") + public ApiResponse signUp(@RequestBody AuthSignupGoogleRequest request) { + final UserDto userDto = authBusiness.signUp(request); - return authBusiness.login(); + return ApiResponse.success(userDto); } // 모바일 로그인 진행 @@ -37,6 +40,13 @@ public ApiResponse loginGoogle(@RequestBody AuthLoginGoogleRequest return ApiResponse.success(jwtResponse); } + // 로그인 url 발행 요청 + @GetMapping("/login") + public URI login() { + + return authBusiness.login(); + } + // 웹 로그인 콜백 주소 @GetMapping("/login/oauth2/code/google") public ApiResponse callbackGoogle(@RequestParam("code") String authorizationCode) { diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/dto/request/AuthSignupGoogleRequest.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/dto/request/AuthSignupGoogleRequest.java new file mode 100644 index 0000000..ec1f3c0 --- /dev/null +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/auth/dto/request/AuthSignupGoogleRequest.java @@ -0,0 +1,12 @@ +package com.nerd.favorite18.core.api.auth.dto.request; + +import com.nerd.favorite18.core.api.auth.model.UserInfo; +import com.nerd.favorite18.core.enums.user.UserGender; +import lombok.Getter; + +@Getter +public class AuthSignupGoogleRequest { + String birth; + UserGender gender; + UserInfo userInfo; +} diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/business/UserBusiness.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/business/UserBusiness.java index 219286f..78e5079 100644 --- a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/business/UserBusiness.java +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/business/UserBusiness.java @@ -17,8 +17,8 @@ public class UserBusiness { * @param user 로그인 유저 정보 * @param request 업데이트할 이름 */ - public void updateNickname(UserDto user, UserUpdateNicknameRequest request) { - userService.updateNickname(user, request); + public UserDto updateNickname(UserDto user, UserUpdateNicknameRequest request) { + return userService.updateNickname(user, request); } /** diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/controller/UserController.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/controller/UserController.java index dba00e8..910323f 100644 --- a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/controller/UserController.java +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/controller/UserController.java @@ -23,10 +23,10 @@ public ApiResponse me(@UserSession UserDto user) { // 사용자 닉네임 변경 @PutMapping("/nickname") - public ApiResponse updateNickname(@UserSession UserDto user, @RequestBody UserUpdateNicknameRequest request) { - userBusiness.updateNickname(user, request); + public ApiResponse updateNickname(@UserSession UserDto user, @RequestBody UserUpdateNicknameRequest request) { + final UserDto userDto = userBusiness.updateNickname(user, request); - return ApiResponse.success(); + return ApiResponse.success(userDto); } // 회원 탈퇴 diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/converter/UserConverter.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/converter/UserConverter.java index 5f11b3d..d5179d1 100644 --- a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/converter/UserConverter.java +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/converter/UserConverter.java @@ -17,6 +17,8 @@ public User toEntity(UserRegisterRequest request) { .subId(request.getSubId()) .email(request.getEmail()) .name(request.getName()) + .birth(request.getBirth()) + .gender(request.getGender()) .thumbnail(request.getThumbnail()) .role(UserRole.USER) .status(UserStatus.ACTIVE) @@ -42,4 +44,23 @@ public UserDto toDto(User entity) { entity.getUpdatedAt() ); } + + public UserDto toDtoWithoutToken(User entity) { + + return UserDto.of( + entity.getId(), + entity.getSubId(), + entity.getEmail(), + entity.getName(), + entity.getNickname(), + entity.getBirth(), + entity.getGender(), + entity.getThumbnail(), + entity.getRole(), + entity.getStatus(), + null, + entity.getCreatedAt(), + entity.getUpdatedAt() + ); + } } diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/dto/request/UserRegisterRequest.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/dto/request/UserRegisterRequest.java index 273a48c..154477f 100644 --- a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/dto/request/UserRegisterRequest.java +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/dto/request/UserRegisterRequest.java @@ -1,13 +1,12 @@ package com.nerd.favorite18.core.api.user.dto.request; +import com.nerd.favorite18.core.enums.user.UserGender; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.Getter; -@Data -@NoArgsConstructor +@Getter @AllArgsConstructor public class UserRegisterRequest { @NotBlank @@ -18,10 +17,19 @@ public class UserRegisterRequest { private String email; private String name; + private String birth; + private UserGender gender; private String thumbnail; - public static UserRegisterRequest of(String subId, String email, String name, String thumbnail) { - return new UserRegisterRequest(subId, email, name, thumbnail); + public static UserRegisterRequest of( + String subId, + String email, + String name, + String birth, + UserGender gender, + String thumbnail + ) { + return new UserRegisterRequest(subId, email, name, birth, gender, thumbnail); } } diff --git a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/service/UserService.java b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/service/UserService.java index 0c57f58..c6031d1 100644 --- a/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/service/UserService.java +++ b/core/core-api/src/main/java/com/nerd/favorite18/core/api/user/service/UserService.java @@ -89,15 +89,16 @@ public UserDto saveUser(UserRegisterRequest request) { * * @param user 로그인 사용자 정보 * @param request 변경할 닉네임 + * @return 사용자 정보 */ @Transactional - public void updateNickname(UserDto user, UserUpdateNicknameRequest request) { + public UserDto updateNickname(UserDto user, UserUpdateNicknameRequest request) { User userEntity = userRepository.findFirstByIdAndStatusOrderByIdDesc(user.getId(), UserStatus.ACTIVE) .orElseThrow(() -> new CoreApiException(ErrorType.USER_NOT_FOUND)); userEntity.updateNickname(request.getNickname()); - userRepository.save(userEntity); + return userConverter.toDtoWithoutToken(userRepository.save(userEntity)); } /** diff --git a/storage/db-core/src/main/java/com/nerd/favorite18/storage/db/core/user/entity/User.java b/storage/db-core/src/main/java/com/nerd/favorite18/storage/db/core/user/entity/User.java index b8ecb9a..0c7d455 100644 --- a/storage/db-core/src/main/java/com/nerd/favorite18/storage/db/core/user/entity/User.java +++ b/storage/db-core/src/main/java/com/nerd/favorite18/storage/db/core/user/entity/User.java @@ -23,11 +23,11 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User extends BaseEntity { @Comment("사용자 ID : provider_sub") - @Column(length = 100, nullable = false) + @Column(unique = true, length = 100, nullable = false) private String subId; @Comment("사용자 이메일") - @Column(length = 50, nullable = false) + @Column(unique = true, length = 50, nullable = false) private String email; @Comment("사용자 이름")