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: 회원가입 및 로그인 구현 #16

Merged
merged 9 commits into from
May 10, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.cakk.api.controller.user;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

import com.cakk.api.dto.request.user.UserSignInRequest;
import com.cakk.api.dto.request.user.UserSignUpRequest;
import com.cakk.api.dto.response.user.JwtResponse;
import com.cakk.api.service.user.UserService;
import com.cakk.common.response.ApiResponse;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 api/v1 앞에 붙는건 환경 변수로 컨트롤하는건 어떤가요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정하겠습니다

public class SignController {

private final UserService userService;

@PostMapping("/sign-up")
public ApiResponse<JwtResponse> signUp(@RequestBody UserSignUpRequest request) {
return ApiResponse.success(userService.signUp(request));
}

@PostMapping("/sign-in")
public ApiResponse<JwtResponse> signIn(@RequestBody UserSignInRequest request) {
return ApiResponse.success(userService.signIn(request));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.cakk.api.dto.request.user;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import com.cakk.common.enums.Provider;

public record UserSignInRequest(
@NotNull
Provider provider,
@NotBlank
String idToken
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.cakk.api.dto.request.user;

import java.time.LocalDate;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import com.cakk.common.enums.Gender;
import com.cakk.common.enums.Provider;

public record UserSignUpRequest(
@NotNull
Provider provider,
@NotBlank
String idToken,
String deviceOs,
String deviceToken,
@NotBlank
String nickname,
@NotBlank
String email,
@NotNull
LocalDate birthday,
@NotNull
Gender gender
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.cakk.api.dto.response.user;

import com.cakk.api.vo.JsonWebToken;

public record JwtResponse(
String accessToken,
String refreshToken,
String grantType
) {

public static JwtResponse from(JsonWebToken jwt) {
return new JwtResponse(jwt.accessToken(), jwt.refreshToken(), jwt.grantType());
}
}
25 changes: 25 additions & 0 deletions cakk-api/src/main/java/com/cakk/api/mapper/UserMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.cakk.api.mapper;

import com.cakk.api.dto.request.user.UserSignUpRequest;
import com.cakk.common.enums.Role;
import com.cakk.domain.entity.user.User;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class UserMapper {

public static User supplyUserBy(UserSignUpRequest dto, String providerId) {
return User.builder()
.provider(dto.provider())
.providerId(providerId)
.nickname(dto.nickname())
.email(dto.email())
.gender(dto.gender())
.birthday(dto.birthday())
.deviceOs(dto.deviceOs())
.deviceToken(dto.deviceToken())
.role(Role.USER)
.build();
}
}
32 changes: 32 additions & 0 deletions cakk-api/src/main/java/com/cakk/api/service/user/UserService.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
package com.cakk.api.service.user;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cakk.api.dto.request.user.UserSignInRequest;
import com.cakk.api.dto.request.user.UserSignUpRequest;
import com.cakk.api.dto.response.user.JwtResponse;
import com.cakk.api.factory.OidcProviderFactory;
import com.cakk.api.mapper.UserMapper;
import com.cakk.api.provider.jwt.JwtProvider;
import com.cakk.domain.entity.user.User;
import com.cakk.domain.repository.reader.UserReader;
import com.cakk.domain.repository.writer.UserWriter;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class UserService {

private final OidcProviderFactory oidcProviderFactory;
private final JwtProvider jwtProvider;

private final UserReader userReader;
private final UserWriter userWriter;

@Transactional
public JwtResponse signUp(UserSignUpRequest dto) {
final String providerId = oidcProviderFactory.getProviderId(dto.provider(), dto.idToken());
final User user = userWriter.create(UserMapper.supplyUserBy(dto, providerId));

return JwtResponse.from(jwtProvider.generateToken(user));
}

@Transactional(readOnly = true)
public JwtResponse signIn(UserSignInRequest dto) {
final String providerId = oidcProviderFactory.getProviderId(dto.provider(), dto.idToken());
final User user = userReader.findByProviderId(providerId);

return JwtResponse.from(jwtProvider.generateToken(user));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum ReturnCode {

// 공통 유저 관련 (1200 ~ 1250)
WRONG_PROVIDER("1200", "잘못된 인증 제공자 입니다."),
NOT_EXIST_USER("1201", "존재하지 않는 유저 입니다."),

// 클라이언트 에러
WRONG_PARAMETER("9000", "잘못된 파라미터 입니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.cakk.domain.repository.jpa;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

import com.cakk.domain.entity.user.User;

public interface UserJpaRepository extends JpaRepository<User, Long> { }
public interface UserJpaRepository extends JpaRepository<User, Long> {

Optional<User> findByProviderId(String providerId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ public class UserReader {
private final UserJpaRepository userJpaRepository;

public User findByUserId(Long userId) {
return userJpaRepository.findById(userId).orElseThrow(() -> new CakkException(ReturnCode.WRONG_PARAMETER));
return userJpaRepository.findById(userId).orElseThrow(() -> new CakkException(ReturnCode.NOT_EXIST_USER));
}

public User findByProviderId(String providerId) {
return userJpaRepository.findByProviderId(providerId).orElseThrow(() -> new CakkException(ReturnCode.NOT_EXIST_USER));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.cakk.domain.repository.writer;

import com.cakk.domain.annotation.Writer;
import com.cakk.domain.entity.user.User;
import com.cakk.domain.repository.jpa.UserJpaRepository;
import lombok.RequiredArgsConstructor;

@Writer
@RequiredArgsConstructor
public class UserWriter {

private final UserJpaRepository userJpaRepository;

public User create(User user) {
return userJpaRepository.save(user);
}
}