Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] 최초 로그인 시 회원가입 로직 구현과 닉네임 수정 기능 구현 #48

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,14 +32,52 @@ public class AuthBusiness {
private final OAuth2Client oauth2Client;

/**
* [ 로그인 요청 ]
* [ 회원가입 ]
* <br/>
* 1. 구글 OAuth2.0 로그인 요청 클라이언트 실행 <br/>
* 1. OAuth2.0 로그인 진행 후 리다이렉트 되어 실행되는 로직 <br/>
*
* @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 ]
* <br/>
* 1. 구글 유저정보 기반으로 DB 에서 유저 조회 <br/>
* 2. 유저 없으면 400 에러 반환 <br/>
* 3. 유저 있으면 바로 유저 조회 결과 반환 <br/>
* 4. 반환된 유저정보 기준으로 Jwt 토큰 발행 <br/>
*
* @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;
}

/**
Expand All @@ -50,27 +91,18 @@ public URI login() {
public JwtResponse loginGoogle(AuthLoginGoogleRequest request) {
GoogleUserInfoMobile googleUserInfo = new GoogleUserInfoMobile(request.getUserInfo());

return checkLoginUser(googleUserInfo);
return checkLoginUserWithError(googleUserInfo);
}

/**
* [ 웹 콜백 로그인 ]
* [ 로그인 요청 ]
* <br/>
* 1. OAuth2.0 로그인 진행 후 리다이렉트 되어 실행되는 로직 <br/>
* 2. 구글 API 에서 AccessToken 받음 <br/>
* 3. 전달받은 AccessToken 으로 유저정보 API 실행 <br/>
* 4. 유저정보로 유저 체크 후 JWT 토큰 발행 <br/>
* 1. 구글 OAuth2.0 로그인 요청 클라이언트 실행 <br/>
*
* @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();
}

/**
Expand All @@ -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())
);
}

Expand All @@ -102,6 +139,26 @@ private JwtResponse checkLoginUser(OAuth2UserInfo userInfo) {
return jwtResponse;
}

/**
* [ 웹 콜백 로그인 ]
* <br/>
* 1. OAuth2.0 로그인 진행 후 리다이렉트 되어 실행되는 로직 <br/>
* 2. 구글 API 에서 AccessToken 받음 <br/>
* 3. 전달받은 AccessToken 으로 유저정보 API 실행 <br/>
* 4. 유저정보로 유저 체크 후 JWT 토큰 발행 <br/>
*
* @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);
}

/**
* [ 리프레쉬 토큰 발행 ]
* <br/>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -22,11 +24,12 @@
public class AuthOpenApiController {
private final AuthBusiness authBusiness;

// 로그인 url 발행 요청
@GetMapping("/login")
public URI login() {
// 모바일 회원가입 진행
@PostMapping("/signup")
public ApiResponse<UserDto> signUp(@RequestBody AuthSignupGoogleRequest request) {
final UserDto userDto = authBusiness.signUp(request);

return authBusiness.login();
return ApiResponse.success(userDto);
}

// 모바일 로그인 진행
Expand All @@ -37,6 +40,13 @@ public ApiResponse<JwtResponse> loginGoogle(@RequestBody AuthLoginGoogleRequest
return ApiResponse.success(jwtResponse);
}

// 로그인 url 발행 요청
@GetMapping("/login")
public URI login() {

return authBusiness.login();
}

// 웹 로그인 콜백 주소
@GetMapping("/login/oauth2/code/google")
public ApiResponse<JwtResponse> callbackGoogle(@RequestParam("code") String authorizationCode) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public ApiResponse<UserDto> me(@UserSession UserDto user) {

// 사용자 닉네임 변경
@PutMapping("/nickname")
public ApiResponse<Void> updateNickname(@UserSession UserDto user, @RequestBody UserUpdateNicknameRequest request) {
userBusiness.updateNickname(user, request);
public ApiResponse<UserDto> updateNickname(@UserSession UserDto user, @RequestBody UserUpdateNicknameRequest request) {
final UserDto userDto = userBusiness.updateNickname(user, request);

return ApiResponse.success();
return ApiResponse.success(userDto);
}

// 회원 탈퇴
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
);
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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("사용자 이름")
Expand Down
Loading