diff --git a/dump.rdb b/dump.rdb index 2e3d3f51..deec2b47 100644 Binary files a/dump.rdb and b/dump.rdb differ diff --git a/src/main/java/kusitms/backend/auth/application/AuthService.java b/src/main/java/kusitms/backend/auth/application/AuthService.java deleted file mode 100644 index 59e6aba4..00000000 --- a/src/main/java/kusitms/backend/auth/application/AuthService.java +++ /dev/null @@ -1,38 +0,0 @@ -package kusitms.backend.auth.application; - -import kusitms.backend.auth.dto.response.TokenResponseDto; -import kusitms.backend.auth.jwt.JWTUtil; -import kusitms.backend.auth.status.AuthErrorStatus; -import kusitms.backend.global.exception.CustomException; -import kusitms.backend.global.redis.RedisManager; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor -public class AuthService { - - private final JWTUtil jwtUtil; - private final RedisManager redisManager; - - /** - * Refresh Token 검증 및 새로운 토큰 발급. - * - * @param refreshToken 클라이언트로부터 받은 리프레시 토큰 - * @return 새로 생성된 Access Token과 Refresh Token - */ - public TokenResponseDto reIssueToken(String refreshToken) { - if (refreshToken == null) { - throw new CustomException(AuthErrorStatus._EXPIRED_REFRESH_TOKEN); - } - - Long userId = redisManager.validateAndExtractUserId(refreshToken); - String newAccessToken = jwtUtil.generateAccessOrRefreshToken(userId, jwtUtil.getAccessTokenExpirationTime()); - String newRefreshToken = jwtUtil.generateAccessOrRefreshToken(userId, jwtUtil.getRefreshTokenExpirationTime()); - - redisManager.saveRefreshToken(userId.toString(), newRefreshToken); - return new TokenResponseDto(newAccessToken, newRefreshToken, jwtUtil.getAccessTokenExpirationTime(), jwtUtil.getRefreshTokenExpirationTime()); - } -} diff --git a/src/main/java/kusitms/backend/auth/presentation/AuthController.java b/src/main/java/kusitms/backend/auth/presentation/AuthController.java deleted file mode 100644 index 1848d338..00000000 --- a/src/main/java/kusitms/backend/auth/presentation/AuthController.java +++ /dev/null @@ -1,47 +0,0 @@ -package kusitms.backend.auth.presentation; - -import jakarta.servlet.http.HttpServletResponse; -import kusitms.backend.auth.application.AuthService; -import kusitms.backend.auth.dto.response.TokenResponseDto; -import kusitms.backend.auth.status.AuthSuccessStatus; -import kusitms.backend.global.dto.ApiResponse; -import kusitms.backend.global.exception.CustomException; -import kusitms.backend.global.util.CookieUtil; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1") -public class AuthController { - - private final AuthService authService; - - /** - * 리프레시 토큰을 통해 새로운 액세스 토큰과 리프레시 토큰을 발급받아 쿠키에 저장합니다. - * - * @param refreshToken 클라이언트로부터 전달받은 리프레시 토큰 (쿠키에서 추출) - * @param response 새로운 토큰을 클라이언트 쿠키에 저장하기 위한 HTTP 응답 객체 - * @return 성공 응답 - * @throws CustomException 리프레시 토큰이 없거나 유효하지 않을 경우 예외 발생 - */ - @PutMapping("/token/re-issue") - public ResponseEntity> reIssueToken( - @CookieValue(value = "refreshToken", required = false) String refreshToken, - HttpServletResponse response - ) { - - // AuthService를 통해 새 토큰 생성 - TokenResponseDto tokenResponseDto = authService.reIssueToken(refreshToken); - - // 새 토큰을 쿠키에 설정 - CookieUtil.setAuthCookies(response, tokenResponseDto.accessToken(), tokenResponseDto.refreshToken(), - tokenResponseDto.accessTokenExpiration(), tokenResponseDto.refreshTokenExpiration()); - - return ApiResponse.onSuccess(AuthSuccessStatus._OK_RE_ISSUE_TOKEN); - } -} diff --git a/src/main/java/kusitms/backend/global/code/BaseCode.java b/src/main/java/kusitms/backend/global/code/BaseCode.java index beabaabf..77dea85d 100644 --- a/src/main/java/kusitms/backend/global/code/BaseCode.java +++ b/src/main/java/kusitms/backend/global/code/BaseCode.java @@ -5,4 +5,4 @@ public interface BaseCode { ReasonDto getReason(); ReasonDto getReasonHttpStatus(); -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/code/BaseErrorCode.java b/src/main/java/kusitms/backend/global/code/BaseErrorCode.java index a1619a8f..611fa558 100644 --- a/src/main/java/kusitms/backend/global/code/BaseErrorCode.java +++ b/src/main/java/kusitms/backend/global/code/BaseErrorCode.java @@ -5,4 +5,4 @@ public interface BaseErrorCode { ErrorReasonDto getReason(); ErrorReasonDto getReasonHttpStatus(); -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/config/QueryDslConfig.java b/src/main/java/kusitms/backend/global/config/QueryDslConfig.java index 4c2ab93d..776a0b17 100644 --- a/src/main/java/kusitms/backend/global/config/QueryDslConfig.java +++ b/src/main/java/kusitms/backend/global/config/QueryDslConfig.java @@ -18,4 +18,4 @@ public class QueryDslConfig { public JPAQueryFactory jpaQueryFactory() { return new JPAQueryFactory(entityManager); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/config/S3Config.java b/src/main/java/kusitms/backend/global/config/S3Config.java index 090da71b..2d259a91 100644 --- a/src/main/java/kusitms/backend/global/config/S3Config.java +++ b/src/main/java/kusitms/backend/global/config/S3Config.java @@ -65,4 +65,4 @@ public void configureS3Cors(AmazonS3 s3) { s3.setBucketCrossOriginConfiguration(bucketName, configuration); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/config/SwaggerConfig.java b/src/main/java/kusitms/backend/global/config/SwaggerConfig.java index e947a5c5..bb004885 100644 --- a/src/main/java/kusitms/backend/global/config/SwaggerConfig.java +++ b/src/main/java/kusitms/backend/global/config/SwaggerConfig.java @@ -48,4 +48,4 @@ public OpenAPI customOpenAPI() { return openAPI; } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/domain/BaseTimeEntity.java b/src/main/java/kusitms/backend/global/domain/BaseTimeEntity.java index 504e4735..fd3c687c 100644 --- a/src/main/java/kusitms/backend/global/domain/BaseTimeEntity.java +++ b/src/main/java/kusitms/backend/global/domain/BaseTimeEntity.java @@ -18,4 +18,4 @@ public class BaseTimeEntity { @LastModifiedDate private LocalDateTime updatedDate; -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/dto/ErrorReasonDto.java b/src/main/java/kusitms/backend/global/dto/ErrorReasonDto.java index a9c4e4c4..9a29c852 100644 --- a/src/main/java/kusitms/backend/global/dto/ErrorReasonDto.java +++ b/src/main/java/kusitms/backend/global/dto/ErrorReasonDto.java @@ -11,4 +11,4 @@ public class ErrorReasonDto { private final boolean isSuccess; private final String code; private final String message; -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/dto/ReasonDto.java b/src/main/java/kusitms/backend/global/dto/ReasonDto.java index 44664719..f56fafb2 100644 --- a/src/main/java/kusitms/backend/global/dto/ReasonDto.java +++ b/src/main/java/kusitms/backend/global/dto/ReasonDto.java @@ -11,4 +11,4 @@ public class ReasonDto { private final boolean isSuccess; private final String code; private final String message; -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/exception/CustomException.java b/src/main/java/kusitms/backend/global/exception/CustomException.java index d0214da3..b7deadd7 100644 --- a/src/main/java/kusitms/backend/global/exception/CustomException.java +++ b/src/main/java/kusitms/backend/global/exception/CustomException.java @@ -22,4 +22,4 @@ public String getCode() { public HttpStatus getHttpStatus() { return errorCode.getReasonHttpStatus().getHttpStatus(); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/redis/RedisManager.java b/src/main/java/kusitms/backend/global/redis/RedisManager.java index 73cc8e50..1898470d 100644 --- a/src/main/java/kusitms/backend/global/redis/RedisManager.java +++ b/src/main/java/kusitms/backend/global/redis/RedisManager.java @@ -1,9 +1,9 @@ package kusitms.backend.global.redis; -import kusitms.backend.auth.jwt.JWTUtil; -import kusitms.backend.auth.status.AuthErrorStatus; import kusitms.backend.global.exception.CustomException; import kusitms.backend.global.status.ErrorStatus; +import kusitms.backend.user.infra.jwt.JWTUtil; +import kusitms.backend.user.status.AuthErrorStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/kusitms/backend/global/status/ErrorStatus.java b/src/main/java/kusitms/backend/global/status/ErrorStatus.java index d7605ec4..fd1dd081 100644 --- a/src/main/java/kusitms/backend/global/status/ErrorStatus.java +++ b/src/main/java/kusitms/backend/global/status/ErrorStatus.java @@ -35,8 +35,10 @@ public enum ErrorStatus implements BaseErrorCode { _RESOURCE_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON-003", "요청한 리소스를 찾을 수 없습니다."), // Cookie Errors - _MISSING_TOKEN_IN_COOKIE(HttpStatus.UNAUTHORIZED, "COOKIE-001", "쿠키에 토큰이 존재하지 않습니다.") - ; + _MISSING_TOKEN_IN_COOKIE(HttpStatus.UNAUTHORIZED, "COOKIE-001", "쿠키에 토큰이 존재하지 않습니다."), + + // Format Errors + _FAILED_FORMAT_PHONE_NUMBER(HttpStatus.BAD_REQUEST, "FORMAT-001", "잘못된 휴대폰 번호 형식입니다. 010-XXXX-XXXX 형식으로 입력해주세요."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/kusitms/backend/global/status/SuccessStatus.java b/src/main/java/kusitms/backend/global/status/SuccessStatus.java index b7542238..868f7693 100644 --- a/src/main/java/kusitms/backend/global/status/SuccessStatus.java +++ b/src/main/java/kusitms/backend/global/status/SuccessStatus.java @@ -36,4 +36,4 @@ public ReasonDto getReasonHttpStatus() { .message(message) .build(); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/global/util/CookieUtil.java b/src/main/java/kusitms/backend/global/util/CookieUtil.java index e28b4682..6ea087a0 100644 --- a/src/main/java/kusitms/backend/global/util/CookieUtil.java +++ b/src/main/java/kusitms/backend/global/util/CookieUtil.java @@ -26,6 +26,17 @@ public static void setAuthCookies(HttpServletResponse response, String accessTok (int) (accessTokenExpiry * 1.5) / 1000); } + /** + * 유저 온보딩을 위한 쿠키를 설정합니다 (Register Token, Expiration Time). + * + * @param response HTTP 응답 객체 + * @param registerToken 레지스터 토큰 + * @param registerTokenExpiry 레지스터 토큰 만료 시간 (밀리초) + */ + public static void setRegisterCookies(HttpServletResponse response, String registerToken, long registerTokenExpiry) { + setCookie(response, "registerToken", registerToken, (int) registerTokenExpiry / 1000); + } + /** * HTTP-Only 쿠키를 설정합니다. * diff --git a/src/main/java/kusitms/backend/global/util/FormatUtil.java b/src/main/java/kusitms/backend/global/util/FormatUtil.java new file mode 100644 index 00000000..ab2b6c02 --- /dev/null +++ b/src/main/java/kusitms/backend/global/util/FormatUtil.java @@ -0,0 +1,26 @@ +package kusitms.backend.global.util; + +import kusitms.backend.global.exception.CustomException; +import kusitms.backend.global.status.ErrorStatus; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class FormatUtil { + + /** + * 전화번호 형식을 010-XXXX-XXXX 형태로 변경한다. + * @param phoneNumber 휴대폰 번호 + * @return 변경된 형식의 전화번호 + */ + public static String formatPhoneNumber(String phoneNumber) { + String pattern = "^010(\\d{4})(\\d{4})$"; + Pattern regex = Pattern.compile(pattern); + Matcher matcher = regex.matcher(phoneNumber.replaceAll("-", "")); // 입력값에서 "-" 제거 + if (matcher.matches()) { + return "010-" + matcher.group(1) + "-" + matcher.group(2); + } else { + throw new CustomException(ErrorStatus._FAILED_FORMAT_PHONE_NUMBER); + } + } +} diff --git a/src/main/java/kusitms/backend/result/application/ResultApplicationService.java b/src/main/java/kusitms/backend/result/application/ResultApplicationService.java index 55270a05..fb5a88d2 100644 --- a/src/main/java/kusitms/backend/result/application/ResultApplicationService.java +++ b/src/main/java/kusitms/backend/result/application/ResultApplicationService.java @@ -1,6 +1,6 @@ package kusitms.backend.result.application; -import kusitms.backend.auth.jwt.JWTUtil; +import kusitms.backend.user.infra.jwt.JWTUtil; import kusitms.backend.result.application.dto.request.SaveTopRankedZoneRequestDto; import kusitms.backend.result.application.dto.response.GetProfileResponseDto; import kusitms.backend.result.application.dto.response.GetZonesResponseDto; diff --git a/src/main/java/kusitms/backend/user/application/UserApplicationService.java b/src/main/java/kusitms/backend/user/application/UserApplicationService.java index 5792d027..9e93c190 100644 --- a/src/main/java/kusitms/backend/user/application/UserApplicationService.java +++ b/src/main/java/kusitms/backend/user/application/UserApplicationService.java @@ -1,23 +1,20 @@ package kusitms.backend.user.application; import jakarta.servlet.http.HttpServletResponse; -import kusitms.backend.auth.dto.response.GoogleUserInfo; -import kusitms.backend.auth.dto.response.KakaoUserInfo; -import kusitms.backend.auth.dto.response.NaverUserInfo; -import kusitms.backend.auth.dto.response.OAuth2UserInfo; -import kusitms.backend.auth.jwt.JWTUtil; -import kusitms.backend.auth.status.AuthErrorStatus; import kusitms.backend.global.exception.CustomException; import kusitms.backend.global.redis.DistributedLockManager; import kusitms.backend.global.redis.RedisManager; -import kusitms.backend.global.util.CookieUtil; -import kusitms.backend.user.domain.entity.User; +import kusitms.backend.user.application.dto.request.CheckNicknameRequestDto; +import kusitms.backend.user.application.dto.request.SendAuthCodeRequestDto; +import kusitms.backend.user.application.dto.request.SignUpRequestDto; +import kusitms.backend.user.application.dto.request.VerifyAuthCodeRequestDto; +import kusitms.backend.user.application.dto.response.*; +import kusitms.backend.user.domain.enums.ProviderStatusType; +import kusitms.backend.user.domain.model.User; import kusitms.backend.user.domain.repository.UserRepository; -import kusitms.backend.user.dto.request.CheckNicknameRequestDto; -import kusitms.backend.user.dto.request.SendAuthCodeRequestDto; -import kusitms.backend.user.dto.request.SignUpRequestDto; -import kusitms.backend.user.dto.request.VerifyAuthCodeRequestDto; -import kusitms.backend.user.dto.response.UserInfoResponseDto; +import kusitms.backend.user.infra.jwt.JWTUtil; +import kusitms.backend.user.infra.sms.SmsManager; +import kusitms.backend.user.status.AuthErrorStatus; import kusitms.backend.user.status.UserErrorStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -31,32 +28,35 @@ @Service @RequiredArgsConstructor public class UserApplicationService { + private final UserRepository userRepository; private final JWTUtil jwtUtil; - private final SmsService smsService; + private final SmsManager smsManager; private final RedisManager redisManager; private final DistributedLockManager distributedLockManager; - + + private static final long LOCK_TIMEOUT = 5000; // 5초 + + /** + * 유저 ID를 통해 DB에 저장된 유저인지 확인한다. + * @param userId 유저 고유 ID + */ @Transactional(readOnly = true) public void validateUserExistsById(Long userId){ - userRepository.findById(userId) - .orElseThrow(() -> new CustomException(UserErrorStatus._NOT_FOUND_USER)); + userRepository.findUserById(userId); log.info("유저 정보 조회 성공"); } - - - private static final long LOCK_TIMEOUT = 5000; // 5초 - /** * OAuth2 사용자 정보 추출 및 신규 여부 확인. * * @param token OAuth2 인증 토큰 * @return 신규 사용자 여부 */ + @Transactional(readOnly = true) public boolean isNewUser(OAuth2AuthenticationToken token) { OAuth2UserInfo oAuth2UserInfo = extractOAuth2UserInfo(token); - return userRepository.findByProviderId(oAuth2UserInfo.getProviderId()) == null; + return userRepository.findUserByProviderId(oAuth2UserInfo.getProviderId()) == null; } /** @@ -65,15 +65,16 @@ public boolean isNewUser(OAuth2AuthenticationToken token) { * @param token OAuth2 인증 토큰 * @param response HTTP 응답 객체 */ - public void handleNewUser(OAuth2AuthenticationToken token, HttpServletResponse response) { + public RegisterTokenResponseDto handleNewUser(OAuth2AuthenticationToken token, HttpServletResponse response) { OAuth2UserInfo oAuth2UserInfo = extractOAuth2UserInfo(token); String registerToken = jwtUtil.generateRegisterToken( oAuth2UserInfo.getProvider(), oAuth2UserInfo.getProviderId(), oAuth2UserInfo.getEmail() ); - CookieUtil.setCookie(response, "registerToken", registerToken, (int) jwtUtil.getRegisterTokenExpirationTime() / 1000); + log.info("신규 사용자 처리 완료: {}", oAuth2UserInfo.getEmail()); + return new RegisterTokenResponseDto(registerToken, jwtUtil.getRegisterTokenExpirationTime()); } /** @@ -82,16 +83,18 @@ public void handleNewUser(OAuth2AuthenticationToken token, HttpServletResponse r * @param token OAuth2 인증 토큰 * @param response HTTP 응답 객체 */ - public void handleExistingUser(OAuth2AuthenticationToken token, HttpServletResponse response) { + @Transactional(readOnly = true) + public AuthTokenResponseDto handleExistingUser(OAuth2AuthenticationToken token, HttpServletResponse response) { OAuth2UserInfo oAuth2UserInfo = extractOAuth2UserInfo(token); - User existUser = userRepository.findByProviderId(oAuth2UserInfo.getProviderId()); + User existUser = userRepository.findUserByProviderId(oAuth2UserInfo.getProviderId()); String accessToken = jwtUtil.generateAccessOrRefreshToken(existUser.getId(), jwtUtil.getAccessTokenExpirationTime()); String refreshToken = jwtUtil.generateAccessOrRefreshToken(existUser.getId(), jwtUtil.getRefreshTokenExpirationTime()); redisManager.saveRefreshToken(existUser.getId().toString(), refreshToken); - CookieUtil.setAuthCookies(response, accessToken, refreshToken, jwtUtil.getAccessTokenExpirationTime(), jwtUtil.getRefreshTokenExpirationTime()); + log.info("기존 사용자 처리 완료: {}", existUser.getId()); + return new AuthTokenResponseDto(accessToken, refreshToken, jwtUtil.getAccessTokenExpirationTime(), jwtUtil.getRefreshTokenExpirationTime()); } /** @@ -118,9 +121,9 @@ private OAuth2UserInfo extractOAuth2UserInfo(OAuth2AuthenticationToken token) { * @param registerToken 회원가입 토큰 * @param request 회원가입 요청 정보 */ - @Transactional - public void signupUser(String registerToken, SignUpRequestDto request) { + public AuthTokenResponseDto signupUser(String registerToken, SignUpRequestDto request) { + if (registerToken == null) { throw new CustomException(AuthErrorStatus._EXPIRED_REGISTER_TOKEN); } @@ -142,15 +145,21 @@ public void signupUser(String registerToken, SignUpRequestDto request) { } }*/ - userRepository.save( - SignUpRequestDto.toEntity( - provider, - providerId, - email, - request.nickname() - ) + User user = User.toDomain( + null, + ProviderStatusType.of(provider), + providerId, + email, + request.nickname() ); + + User savedUser = userRepository.saveUser(user); + String accessToken = jwtUtil.generateAccessOrRefreshToken(savedUser.getId(), jwtUtil.getAccessTokenExpirationTime()); + String refreshToken = jwtUtil.generateAccessOrRefreshToken(savedUser.getId(), jwtUtil.getRefreshTokenExpirationTime()); + + redisManager.saveRefreshToken(savedUser.getId().toString(), refreshToken); log.info("회원가입 성공: {}", email); + return new AuthTokenResponseDto(accessToken, refreshToken, jwtUtil.getAccessTokenExpirationTime(), jwtUtil.getRefreshTokenExpirationTime()); } /** @@ -162,8 +171,7 @@ public void signupUser(String registerToken, SignUpRequestDto request) { @Transactional(readOnly = true) public UserInfoResponseDto getUserInfo(String accessToken) { Long userId = jwtUtil.getUserIdFromToken(accessToken); - User user = userRepository.findById(userId) - .orElseThrow(() -> new CustomException(UserErrorStatus._NOT_FOUND_USER)); + User user = userRepository.findUserById(userId); log.info("사용자 정보 조회 성공: {}", userId); return UserInfoResponseDto.from(user); } @@ -176,7 +184,7 @@ public UserInfoResponseDto getUserInfo(String accessToken) { public void sendAuthCode(SendAuthCodeRequestDto request) { String authCode = generateAuthCode(); redisManager.savePhoneVerificationCode(request.phoneNumber(), authCode); - smsService.sendSms(request.phoneNumber(), "히트존 인증 코드 번호 : " + authCode); + smsManager.sendSms(request.phoneNumber(), "히트존 인증 코드 번호 : " + authCode); log.info("인증 코드 발송 완료: {}", request.phoneNumber()); } @@ -224,7 +232,7 @@ public void checkNickname(CheckNicknameRequestDto request) { try { // 2. 닉네임 중복 확인 - User user = userRepository.findByNickname(nickname); + User user = userRepository.findUserByNickname(nickname); if (user != null) { throw new CustomException(UserErrorStatus._DUPLICATED_NICKNAME); } @@ -235,4 +243,23 @@ public void checkNickname(CheckNicknameRequestDto request) { distributedLockManager.releaseLock(lockKey); } } + + /** + * Refresh Token 검증 및 새로운 토큰 발급. + * + * @param refreshToken 클라이언트로부터 받은 리프레시 토큰 + * @return 새로 생성된 Access Token과 Refresh Token + */ + public AuthTokenResponseDto reIssueToken(String refreshToken) { + if (refreshToken == null) { + throw new CustomException(AuthErrorStatus._EXPIRED_REFRESH_TOKEN); + } + + Long userId = redisManager.validateAndExtractUserId(refreshToken); + String newAccessToken = jwtUtil.generateAccessOrRefreshToken(userId, jwtUtil.getAccessTokenExpirationTime()); + String newRefreshToken = jwtUtil.generateAccessOrRefreshToken(userId, jwtUtil.getRefreshTokenExpirationTime()); + + redisManager.saveRefreshToken(userId.toString(), newRefreshToken); + return new AuthTokenResponseDto(newAccessToken, newRefreshToken, jwtUtil.getAccessTokenExpirationTime(), jwtUtil.getRefreshTokenExpirationTime()); + } } diff --git a/src/main/java/kusitms/backend/user/dto/request/CheckNicknameRequestDto.java b/src/main/java/kusitms/backend/user/application/dto/request/CheckNicknameRequestDto.java similarity index 78% rename from src/main/java/kusitms/backend/user/dto/request/CheckNicknameRequestDto.java rename to src/main/java/kusitms/backend/user/application/dto/request/CheckNicknameRequestDto.java index e1b7f4b2..a243a20f 100644 --- a/src/main/java/kusitms/backend/user/dto/request/CheckNicknameRequestDto.java +++ b/src/main/java/kusitms/backend/user/application/dto/request/CheckNicknameRequestDto.java @@ -1,4 +1,4 @@ -package kusitms.backend.user.dto.request; +package kusitms.backend.user.application.dto.request; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/kusitms/backend/user/dto/request/SendAuthCodeRequestDto.java b/src/main/java/kusitms/backend/user/application/dto/request/SendAuthCodeRequestDto.java similarity index 78% rename from src/main/java/kusitms/backend/user/dto/request/SendAuthCodeRequestDto.java rename to src/main/java/kusitms/backend/user/application/dto/request/SendAuthCodeRequestDto.java index 94352503..38a5a70e 100644 --- a/src/main/java/kusitms/backend/user/dto/request/SendAuthCodeRequestDto.java +++ b/src/main/java/kusitms/backend/user/application/dto/request/SendAuthCodeRequestDto.java @@ -1,8 +1,8 @@ -package kusitms.backend.user.dto.request; +package kusitms.backend.user.application.dto.request; import jakarta.validation.constraints.NotBlank; public record SendAuthCodeRequestDto( @NotBlank(message = "휴대폰 번호는 공백이나 빈칸일 수 없습니다.") String phoneNumber ) { -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/user/application/dto/request/SignUpRequestDto.java b/src/main/java/kusitms/backend/user/application/dto/request/SignUpRequestDto.java new file mode 100644 index 00000000..d3675ad8 --- /dev/null +++ b/src/main/java/kusitms/backend/user/application/dto/request/SignUpRequestDto.java @@ -0,0 +1,8 @@ +package kusitms.backend.user.application.dto.request; + +import jakarta.validation.constraints.NotBlank; + +public record SignUpRequestDto( + @NotBlank(message = "닉네임은 공백이나 빈칸일 수 없습니다.") String nickname +) { +} diff --git a/src/main/java/kusitms/backend/user/dto/request/VerifyAuthCodeRequestDto.java b/src/main/java/kusitms/backend/user/application/dto/request/VerifyAuthCodeRequestDto.java similarity index 85% rename from src/main/java/kusitms/backend/user/dto/request/VerifyAuthCodeRequestDto.java rename to src/main/java/kusitms/backend/user/application/dto/request/VerifyAuthCodeRequestDto.java index 0b89e91a..6340bdfc 100644 --- a/src/main/java/kusitms/backend/user/dto/request/VerifyAuthCodeRequestDto.java +++ b/src/main/java/kusitms/backend/user/application/dto/request/VerifyAuthCodeRequestDto.java @@ -1,4 +1,4 @@ -package kusitms.backend.user.dto.request; +package kusitms.backend.user.application.dto.request; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/kusitms/backend/auth/dto/response/TokenResponseDto.java b/src/main/java/kusitms/backend/user/application/dto/response/AuthTokenResponseDto.java similarity index 59% rename from src/main/java/kusitms/backend/auth/dto/response/TokenResponseDto.java rename to src/main/java/kusitms/backend/user/application/dto/response/AuthTokenResponseDto.java index a1f61b2d..298b3d15 100644 --- a/src/main/java/kusitms/backend/auth/dto/response/TokenResponseDto.java +++ b/src/main/java/kusitms/backend/user/application/dto/response/AuthTokenResponseDto.java @@ -1,6 +1,6 @@ -package kusitms.backend.auth.dto.response; +package kusitms.backend.user.application.dto.response; -public record TokenResponseDto( +public record AuthTokenResponseDto( String accessToken, String refreshToken, long accessTokenExpiration, diff --git a/src/main/java/kusitms/backend/auth/dto/response/GoogleUserInfo.java b/src/main/java/kusitms/backend/user/application/dto/response/GoogleUserInfo.java similarity index 91% rename from src/main/java/kusitms/backend/auth/dto/response/GoogleUserInfo.java rename to src/main/java/kusitms/backend/user/application/dto/response/GoogleUserInfo.java index 5b25a826..06c2f61a 100644 --- a/src/main/java/kusitms/backend/auth/dto/response/GoogleUserInfo.java +++ b/src/main/java/kusitms/backend/user/application/dto/response/GoogleUserInfo.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.dto.response; +package kusitms.backend.user.application.dto.response; import lombok.AllArgsConstructor; diff --git a/src/main/java/kusitms/backend/auth/dto/response/KakaoUserInfo.java b/src/main/java/kusitms/backend/user/application/dto/response/KakaoUserInfo.java similarity index 91% rename from src/main/java/kusitms/backend/auth/dto/response/KakaoUserInfo.java rename to src/main/java/kusitms/backend/user/application/dto/response/KakaoUserInfo.java index 81b79fc5..abd76e71 100644 --- a/src/main/java/kusitms/backend/auth/dto/response/KakaoUserInfo.java +++ b/src/main/java/kusitms/backend/user/application/dto/response/KakaoUserInfo.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.dto.response; +package kusitms.backend.user.application.dto.response; import lombok.AllArgsConstructor; @@ -28,4 +28,4 @@ public String getEmail() { public String getName() { return ((Map) attribute.get("properties")).get("nickname").toString(); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/auth/dto/response/NaverUserInfo.java b/src/main/java/kusitms/backend/user/application/dto/response/NaverUserInfo.java similarity index 92% rename from src/main/java/kusitms/backend/auth/dto/response/NaverUserInfo.java rename to src/main/java/kusitms/backend/user/application/dto/response/NaverUserInfo.java index 89248730..3ecf381e 100644 --- a/src/main/java/kusitms/backend/auth/dto/response/NaverUserInfo.java +++ b/src/main/java/kusitms/backend/user/application/dto/response/NaverUserInfo.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.dto.response; +package kusitms.backend.user.application.dto.response; import lombok.AllArgsConstructor; diff --git a/src/main/java/kusitms/backend/auth/dto/response/OAuth2UserInfo.java b/src/main/java/kusitms/backend/user/application/dto/response/OAuth2UserInfo.java similarity index 84% rename from src/main/java/kusitms/backend/auth/dto/response/OAuth2UserInfo.java rename to src/main/java/kusitms/backend/user/application/dto/response/OAuth2UserInfo.java index feb8b0fb..4d076628 100644 --- a/src/main/java/kusitms/backend/auth/dto/response/OAuth2UserInfo.java +++ b/src/main/java/kusitms/backend/user/application/dto/response/OAuth2UserInfo.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.dto.response; +package kusitms.backend.user.application.dto.response; public interface OAuth2UserInfo { //제공자 (Ex. naver, google, ...) diff --git a/src/main/java/kusitms/backend/user/application/dto/response/RegisterTokenResponseDto.java b/src/main/java/kusitms/backend/user/application/dto/response/RegisterTokenResponseDto.java new file mode 100644 index 00000000..f49636ef --- /dev/null +++ b/src/main/java/kusitms/backend/user/application/dto/response/RegisterTokenResponseDto.java @@ -0,0 +1,7 @@ +package kusitms.backend.user.application.dto.response; + +public record RegisterTokenResponseDto( + String registerToken, + long registerTokenExpiration +) { +} diff --git a/src/main/java/kusitms/backend/user/dto/response/UserInfoResponseDto.java b/src/main/java/kusitms/backend/user/application/dto/response/UserInfoResponseDto.java similarity index 72% rename from src/main/java/kusitms/backend/user/dto/response/UserInfoResponseDto.java rename to src/main/java/kusitms/backend/user/application/dto/response/UserInfoResponseDto.java index d25f7af5..bf557546 100644 --- a/src/main/java/kusitms/backend/user/dto/response/UserInfoResponseDto.java +++ b/src/main/java/kusitms/backend/user/application/dto/response/UserInfoResponseDto.java @@ -1,6 +1,6 @@ -package kusitms.backend.user.dto.response; +package kusitms.backend.user.application.dto.response; -import kusitms.backend.user.domain.entity.User; +import kusitms.backend.user.domain.model.User; public record UserInfoResponseDto ( String nickname, diff --git a/src/main/java/kusitms/backend/user/domain/model/User.java b/src/main/java/kusitms/backend/user/domain/model/User.java new file mode 100644 index 00000000..c2964ea5 --- /dev/null +++ b/src/main/java/kusitms/backend/user/domain/model/User.java @@ -0,0 +1,42 @@ +package kusitms.backend.user.domain.model; + +import kusitms.backend.user.domain.enums.ProviderStatusType; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class User { + + private Long id; + private ProviderStatusType provider; + private String providerId; + private String email; + private String nickname; +// private String phoneNumber; + + public User( + Long id, + ProviderStatusType provider, + String providerId, + String email, + String nickname + ) { + this.id = id; + this.provider = provider; + this.providerId = providerId; + this.email = email; + this.nickname = nickname; + } + + public static User toDomain( + Long id, + ProviderStatusType provider, + String providerId, + String email, + String nickname + ) { + return new User(id, provider, providerId, email, nickname); + } +} diff --git a/src/main/java/kusitms/backend/user/domain/repository/UserRepository.java b/src/main/java/kusitms/backend/user/domain/repository/UserRepository.java index ef9c1f83..8730ee45 100644 --- a/src/main/java/kusitms/backend/user/domain/repository/UserRepository.java +++ b/src/main/java/kusitms/backend/user/domain/repository/UserRepository.java @@ -1,10 +1,13 @@ package kusitms.backend.user.domain.repository; -import kusitms.backend.user.domain.entity.User; -import org.springframework.data.jpa.repository.JpaRepository; +import kusitms.backend.user.domain.model.User; +import org.springframework.stereotype.Repository; -public interface UserRepository extends JpaRepository { - User findByProviderId(String providerId); - User findByNickname(String nickname); -// User findByPhoneNumber(String phoneNumber); +@Repository +public interface UserRepository { + User findUserById(Long id); + User findUserByProviderId(String providerId); + User findUserByNickname(String nickname); + User saveUser(User user); +// User findUserByPhoneNumber(String phoneNumber); } diff --git a/src/main/java/kusitms/backend/user/dto/request/SignUpRequestDto.java b/src/main/java/kusitms/backend/user/dto/request/SignUpRequestDto.java deleted file mode 100644 index c115d52c..00000000 --- a/src/main/java/kusitms/backend/user/dto/request/SignUpRequestDto.java +++ /dev/null @@ -1,33 +0,0 @@ -package kusitms.backend.user.dto.request; - -import jakarta.validation.constraints.NotBlank; -import kusitms.backend.user.domain.entity.User; -import kusitms.backend.user.domain.enums.ProviderStatusType; - -public record SignUpRequestDto( - @NotBlank(message = "닉네임은 공백이나 빈칸일 수 없습니다.") String nickname -) { - public static User toEntity(String provider, String providerId, String email, String nickname) { - return User.builder() - .provider(ProviderStatusType.of(provider)) - .providerId(providerId) - .email(email) - .nickname(nickname) - .build(); - } - - // 전화번호를 010-xxxx-xxxx 형식으로 변환 -// private static String formatPhoneNumber(String phoneNumber) { -// String pattern = "^010(\\d{4})(\\d{4})$"; -// Pattern regex = Pattern.compile(pattern); -// // "-"를 제거한 후 정규식과 매칭 시도 -// Matcher matcher = regex.matcher(phoneNumber.replaceAll("-", "")); // 입력값에서 "-" 제거 -// // 정규식이 맞으면 010-xxxx-xxxx 형식으로 변환 -// if (matcher.matches()) { -// return "010-" + matcher.group(1) + "-" + matcher.group(2); // 010-xxxx-xxxx 형식으로 변환 -// } else { -// // 정규식에 맞지 않으면 예외 발생 -// throw new CustomException(UserErrorStatus._BAD_REQUEST_PHONE_NUMBER_TYPE); -// } -// } -} diff --git a/src/main/java/kusitms/backend/global/config/SecurityConfig.java b/src/main/java/kusitms/backend/user/infra/config/SecurityConfig.java similarity index 89% rename from src/main/java/kusitms/backend/global/config/SecurityConfig.java rename to src/main/java/kusitms/backend/user/infra/config/SecurityConfig.java index 4314ff95..1e2ca93d 100644 --- a/src/main/java/kusitms/backend/global/config/SecurityConfig.java +++ b/src/main/java/kusitms/backend/user/infra/config/SecurityConfig.java @@ -1,9 +1,9 @@ -package kusitms.backend.global.config; +package kusitms.backend.user.infra.config; -import kusitms.backend.auth.handler.OAuth2LoginFailureHandler; -import kusitms.backend.auth.handler.OAuth2LoginSuccessHandler; -import kusitms.backend.auth.jwt.JWTFilter; -import kusitms.backend.auth.jwt.JWTUtil; +import kusitms.backend.user.infra.handler.OAuth2LoginFailureHandler; +import kusitms.backend.user.infra.handler.OAuth2LoginSuccessHandler; +import kusitms.backend.user.infra.jwt.JWTFilter; +import kusitms.backend.user.infra.jwt.JWTUtil; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -47,9 +47,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/onboarding", "/base", "/api/v1/health-check", "/api/v1/test-error", "/api/v1/test/docs","/swagger-ui/**", "/v3/api-docs/**", - "/api/v1/signup", "/api/v1/nickname/check", - "/api/v1/send-code","/api/v1/verify-code", - "/api/v1/token/re-issue", + "/api/v1/user/**", "/api/v1/results/**", "/api/v1/stadium/**", "/api/v1/foods", "/api/v1/entertainments", "/api/v1/chatbot/**").permitAll() // 인증이 필요 없는 경로 설정 @@ -79,4 +77,4 @@ public CorsConfigurationSource corsConfigurationSource() { source.registerCorsConfiguration("/**", configuration); return source; } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/auth/handler/OAuth2LoginFailureHandler.java b/src/main/java/kusitms/backend/user/infra/handler/OAuth2LoginFailureHandler.java similarity index 95% rename from src/main/java/kusitms/backend/auth/handler/OAuth2LoginFailureHandler.java rename to src/main/java/kusitms/backend/user/infra/handler/OAuth2LoginFailureHandler.java index 2336bf32..2d1c868a 100644 --- a/src/main/java/kusitms/backend/auth/handler/OAuth2LoginFailureHandler.java +++ b/src/main/java/kusitms/backend/user/infra/handler/OAuth2LoginFailureHandler.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.handler; +package kusitms.backend.user.infra.handler; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/kusitms/backend/auth/handler/OAuth2LoginSuccessHandler.java b/src/main/java/kusitms/backend/user/infra/handler/OAuth2LoginSuccessHandler.java similarity index 64% rename from src/main/java/kusitms/backend/auth/handler/OAuth2LoginSuccessHandler.java rename to src/main/java/kusitms/backend/user/infra/handler/OAuth2LoginSuccessHandler.java index 0e7a27ae..b60b5093 100644 --- a/src/main/java/kusitms/backend/auth/handler/OAuth2LoginSuccessHandler.java +++ b/src/main/java/kusitms/backend/user/infra/handler/OAuth2LoginSuccessHandler.java @@ -1,9 +1,12 @@ -package kusitms.backend.auth.handler; +package kusitms.backend.user.infra.handler; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import kusitms.backend.auth.jwt.JWTUtil; +import kusitms.backend.global.util.CookieUtil; import kusitms.backend.user.application.UserApplicationService; +import kusitms.backend.user.application.dto.response.AuthTokenResponseDto; +import kusitms.backend.user.application.dto.response.RegisterTokenResponseDto; +import kusitms.backend.user.infra.jwt.JWTUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.Authentication; @@ -35,12 +38,15 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo // 신규 사용자 처리 if (userApplicationService.isNewUser(token)) { - userApplicationService.handleNewUser(token, response); + RegisterTokenResponseDto registerTokenResponseDto = userApplicationService.handleNewUser(token, response); + CookieUtil.setRegisterCookies(response, registerTokenResponseDto.registerToken(), registerTokenResponseDto.registerTokenExpiration()); getRedirectStrategy().sendRedirect(request, response, jwtUtil.getRedirectOnboardingUrl()); } // 기존 사용자 처리 else { - userApplicationService.handleExistingUser(token, response); + AuthTokenResponseDto authTokenResponseDto = userApplicationService.handleExistingUser(token, response); + CookieUtil.setAuthCookies(response, authTokenResponseDto.accessToken(), authTokenResponseDto.refreshToken(), + authTokenResponseDto.accessTokenExpiration(), authTokenResponseDto.refreshTokenExpiration()); getRedirectStrategy().sendRedirect(request, response, jwtUtil.getRedirectBaseUrl()); } } diff --git a/src/main/java/kusitms/backend/user/domain/entity/User.java b/src/main/java/kusitms/backend/user/infra/jpa/entity/UserEntity.java similarity index 63% rename from src/main/java/kusitms/backend/user/domain/entity/User.java rename to src/main/java/kusitms/backend/user/infra/jpa/entity/UserEntity.java index 1943187c..2b33afef 100644 --- a/src/main/java/kusitms/backend/user/domain/entity/User.java +++ b/src/main/java/kusitms/backend/user/infra/jpa/entity/UserEntity.java @@ -1,10 +1,9 @@ -package kusitms.backend.user.domain.entity; +package kusitms.backend.user.infra.jpa.entity; import jakarta.persistence.*; import kusitms.backend.global.domain.BaseTimeEntity; import kusitms.backend.user.domain.enums.ProviderStatusType; import lombok.AccessLevel; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -12,7 +11,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(name="users") -public class User extends BaseTimeEntity { +public class UserEntity extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -35,11 +34,27 @@ public class User extends BaseTimeEntity { // @Column(nullable = false, unique = true) // private String phoneNumber; - @Builder - public User(ProviderStatusType provider, String providerId, String email, String nickname) { + public UserEntity( + Long id, + ProviderStatusType provider, + String providerId, + String email, + String nickname + ) { + this.id = id; this.provider = provider; this.providerId = providerId; this.email = email; this.nickname = nickname; } + + public static UserEntity toEntity( + Long id, + ProviderStatusType provider, + String providerId, + String email, + String nickname + ) { + return new UserEntity(id, provider, providerId, email, nickname); + } } diff --git a/src/main/java/kusitms/backend/user/infra/jpa/repository/UserJpaRepository.java b/src/main/java/kusitms/backend/user/infra/jpa/repository/UserJpaRepository.java new file mode 100644 index 00000000..c128168f --- /dev/null +++ b/src/main/java/kusitms/backend/user/infra/jpa/repository/UserJpaRepository.java @@ -0,0 +1,10 @@ +package kusitms.backend.user.infra.jpa.repository; + +import kusitms.backend.user.infra.jpa.entity.UserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserJpaRepository extends JpaRepository { + UserEntity findByProviderId(String providerId); + UserEntity findByNickname(String nickname); +// UserEntity findByPhoneNumber(String phoneNumber); +} diff --git a/src/main/java/kusitms/backend/user/infra/jpa/repositoryImpl/UserRepositoryImpl.java b/src/main/java/kusitms/backend/user/infra/jpa/repositoryImpl/UserRepositoryImpl.java new file mode 100644 index 00000000..ad21fbe2 --- /dev/null +++ b/src/main/java/kusitms/backend/user/infra/jpa/repositoryImpl/UserRepositoryImpl.java @@ -0,0 +1,49 @@ +package kusitms.backend.user.infra.jpa.repositoryImpl; + +import kusitms.backend.global.exception.CustomException; +import kusitms.backend.user.domain.model.User; +import kusitms.backend.user.domain.repository.UserRepository; +import kusitms.backend.user.infra.jpa.entity.UserEntity; +import kusitms.backend.user.infra.jpa.repository.UserJpaRepository; +import kusitms.backend.user.infra.mapper.UserMapper; +import kusitms.backend.user.status.UserErrorStatus; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class UserRepositoryImpl implements UserRepository { + + private final UserJpaRepository userJpaRepository; + + @Override + public User findUserById(Long id) { + UserEntity userEntity = userJpaRepository.findById(id) + .orElseThrow(() -> new CustomException(UserErrorStatus._NOT_FOUND_USER)); + return UserMapper.toDomain(userEntity); + } + + @Override + public User findUserByProviderId(String providerId) { + UserEntity userEntity = userJpaRepository.findByProviderId(providerId); + if (userEntity == null) { + return null; + } + return UserMapper.toDomain(userEntity); + } + + @Override + public User findUserByNickname(String nickname) { + UserEntity userEntity = userJpaRepository.findByNickname(nickname); + if (userEntity == null) { + return null; + } + return UserMapper.toDomain(userEntity); + } + + @Override + public User saveUser(User user) { + UserEntity userEntity = userJpaRepository.save(UserMapper.toEntity(user)); + return UserMapper.toDomain(userEntity); + } +} diff --git a/src/main/java/kusitms/backend/auth/jwt/JWTFilter.java b/src/main/java/kusitms/backend/user/infra/jwt/JWTFilter.java similarity index 93% rename from src/main/java/kusitms/backend/auth/jwt/JWTFilter.java rename to src/main/java/kusitms/backend/user/infra/jwt/JWTFilter.java index 64f18225..253c53b7 100644 --- a/src/main/java/kusitms/backend/auth/jwt/JWTFilter.java +++ b/src/main/java/kusitms/backend/user/infra/jwt/JWTFilter.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.jwt; +package kusitms.backend.user.infra.jwt; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -46,10 +46,8 @@ protected boolean shouldNotFilter(HttpServletRequest request) { return path.equals("/") || path.startsWith("/login") || path.startsWith("/public") || path.equals("/api/v1/test-error") || path.equals("/api/v1/health-check") || path.equals("/onboarding") || path.equals("/base") - || path.equals("/api/v1/signup") || path.equals("/api/v1/nickname/check") - || path.equals("/api/v1/send-code") || path.equals("/api/v1/verify-code") - || path.equals("/api/v1/token/re-issue") || path.equals("/api/v1/test/docs") || path.startsWith(("/swagger-ui")) || path.startsWith("/v3/api-docs") + || path.startsWith("/api/v1/user") || path.startsWith("/api/v1/results") || path.startsWith("/api/v1/stadium") || path.equals("/api/v1/foods") || path.equals("/api/v1/entertainments") || path.startsWith("/api/v1/chatbot") @@ -82,4 +80,4 @@ private void handleException(HttpServletResponse response, Exception e) throws I String jsonResponse = String.format("{\"code\": \"%s\", \"message\": \"%s\", \"isSuccess\": \"false\"}", "500", e.getMessage()); response.getWriter().write(jsonResponse); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/auth/jwt/JWTUtil.java b/src/main/java/kusitms/backend/user/infra/jwt/JWTUtil.java similarity index 98% rename from src/main/java/kusitms/backend/auth/jwt/JWTUtil.java rename to src/main/java/kusitms/backend/user/infra/jwt/JWTUtil.java index 8b3578df..586f4e64 100644 --- a/src/main/java/kusitms/backend/auth/jwt/JWTUtil.java +++ b/src/main/java/kusitms/backend/user/infra/jwt/JWTUtil.java @@ -1,12 +1,12 @@ -package kusitms.backend.auth.jwt; +package kusitms.backend.user.infra.jwt; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; -import kusitms.backend.auth.status.AuthErrorStatus; import kusitms.backend.global.exception.CustomException; +import kusitms.backend.user.status.AuthErrorStatus; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/kusitms/backend/auth/jwt/JwtProperties.java b/src/main/java/kusitms/backend/user/infra/jwt/JwtProperties.java similarity index 92% rename from src/main/java/kusitms/backend/auth/jwt/JwtProperties.java rename to src/main/java/kusitms/backend/user/infra/jwt/JwtProperties.java index e9d9f800..54f0b76a 100644 --- a/src/main/java/kusitms/backend/auth/jwt/JwtProperties.java +++ b/src/main/java/kusitms/backend/user/infra/jwt/JwtProperties.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.jwt; +package kusitms.backend.user.infra.jwt; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/kusitms/backend/auth/jwt/SecurityContextProvider.java b/src/main/java/kusitms/backend/user/infra/jwt/SecurityContextProvider.java similarity index 91% rename from src/main/java/kusitms/backend/auth/jwt/SecurityContextProvider.java rename to src/main/java/kusitms/backend/user/infra/jwt/SecurityContextProvider.java index cb319986..814418af 100644 --- a/src/main/java/kusitms/backend/auth/jwt/SecurityContextProvider.java +++ b/src/main/java/kusitms/backend/user/infra/jwt/SecurityContextProvider.java @@ -1,7 +1,7 @@ -package kusitms.backend.auth.jwt; +package kusitms.backend.user.infra.jwt; -import kusitms.backend.auth.status.AuthErrorStatus; import kusitms.backend.global.exception.CustomException; +import kusitms.backend.user.status.AuthErrorStatus; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; diff --git a/src/main/java/kusitms/backend/auth/jwt/UserAuthentication.java b/src/main/java/kusitms/backend/user/infra/jwt/UserAuthentication.java similarity index 91% rename from src/main/java/kusitms/backend/auth/jwt/UserAuthentication.java rename to src/main/java/kusitms/backend/user/infra/jwt/UserAuthentication.java index 8812bfa0..ba710afa 100644 --- a/src/main/java/kusitms/backend/auth/jwt/UserAuthentication.java +++ b/src/main/java/kusitms/backend/user/infra/jwt/UserAuthentication.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.jwt; +package kusitms.backend.user.infra.jwt; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; diff --git a/src/main/java/kusitms/backend/user/infra/mapper/UserMapper.java b/src/main/java/kusitms/backend/user/infra/mapper/UserMapper.java new file mode 100644 index 00000000..31807267 --- /dev/null +++ b/src/main/java/kusitms/backend/user/infra/mapper/UserMapper.java @@ -0,0 +1,27 @@ +package kusitms.backend.user.infra.mapper; + +import kusitms.backend.user.domain.model.User; +import kusitms.backend.user.infra.jpa.entity.UserEntity; + +public class UserMapper { + + public static User toDomain(UserEntity userEntity) { + return User.toDomain( + userEntity.getId(), + userEntity.getProvider(), + userEntity.getProviderId(), + userEntity.getEmail(), + userEntity.getNickname() + ); + } + + public static UserEntity toEntity(User user) { + return UserEntity.toEntity( + user.getId(), + user.getProvider(), + user.getProviderId(), + user.getEmail(), + user.getNickname() + ); + } +} diff --git a/src/main/java/kusitms/backend/user/application/SmsService.java b/src/main/java/kusitms/backend/user/infra/sms/SmsManager.java similarity index 89% rename from src/main/java/kusitms/backend/user/application/SmsService.java rename to src/main/java/kusitms/backend/user/infra/sms/SmsManager.java index c6cc14cc..6d9a54f7 100644 --- a/src/main/java/kusitms/backend/user/application/SmsService.java +++ b/src/main/java/kusitms/backend/user/infra/sms/SmsManager.java @@ -1,14 +1,14 @@ -package kusitms.backend.user.application; +package kusitms.backend.user.infra.sms; import com.twilio.Twilio; import com.twilio.rest.api.v2010.account.Message; import com.twilio.type.PhoneNumber; import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; -@Service -public class SmsService { +@Component +public class SmsManager { @Value("${twilio.account_sid}") private String accountSid; @@ -33,4 +33,4 @@ public void sendSms(String to, String message) { message // 메시지 내용 ).create(); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/user/presentation/UserController.java b/src/main/java/kusitms/backend/user/presentation/UserController.java index a563bdc2..e81fb091 100644 --- a/src/main/java/kusitms/backend/user/presentation/UserController.java +++ b/src/main/java/kusitms/backend/user/presentation/UserController.java @@ -1,11 +1,16 @@ package kusitms.backend.user.presentation; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import kusitms.backend.global.dto.ApiResponse; +import kusitms.backend.global.exception.CustomException; +import kusitms.backend.global.util.CookieUtil; import kusitms.backend.user.application.UserApplicationService; -import kusitms.backend.user.dto.request.CheckNicknameRequestDto; -import kusitms.backend.user.dto.request.SignUpRequestDto; -import kusitms.backend.user.dto.response.UserInfoResponseDto; +import kusitms.backend.user.application.dto.request.CheckNicknameRequestDto; +import kusitms.backend.user.application.dto.request.SignUpRequestDto; +import kusitms.backend.user.application.dto.response.AuthTokenResponseDto; +import kusitms.backend.user.application.dto.response.UserInfoResponseDto; +import kusitms.backend.user.status.AuthSuccessStatus; import kusitms.backend.user.status.UserSuccessStatus; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -13,37 +18,47 @@ @RestController @RequiredArgsConstructor -@RequestMapping("/api/v1") +@RequestMapping("/api/v1/user") public class UserController { + private final UserApplicationService userApplicationService; /** - * 유저 회원가입을 진행한다. - * @return X + * 레지스터 토큰에서 추출한 정보들과 닉네임으로 회원가입을 진행한다. + * @param registerToken 쿠키로부터 받은 레지스터 토큰 + * @param request 닉네임 + * @return void */ @PostMapping("/signup") public ResponseEntity> signupUser( @CookieValue(required = false) String registerToken, - @Valid @RequestBody SignUpRequestDto request + @Valid @RequestBody SignUpRequestDto request, + HttpServletResponse response ) { - userApplicationService.signupUser(registerToken, request); + AuthTokenResponseDto authTokenResponseDto = userApplicationService.signupUser(registerToken, request); + CookieUtil.setAuthCookies(response, authTokenResponseDto.accessToken(), authTokenResponseDto.refreshToken(), + authTokenResponseDto.accessTokenExpiration(), authTokenResponseDto.refreshTokenExpiration()); + return ApiResponse.onSuccess(UserSuccessStatus._CREATED_USER); } /** - * 유저 정보를 조회한다. - * @return 닉네임, 이메일 + * 쿠키를 통한 인가를 통해 유저 정보를 조회한다. + * @param accessToken 쿠키로부터 받은 어세스 토큰 + * @return 유저 닉네임, 이메일 */ - @GetMapping("/user-info") + @GetMapping("/info") public ResponseEntity> getUserInfo( @CookieValue String accessToken ) { - return ApiResponse.onSuccess(UserSuccessStatus._OK_GET_USER_INFO, userApplicationService.getUserInfo(accessToken)); + UserInfoResponseDto userInfoResponseDto = userApplicationService.getUserInfo(accessToken); + return ApiResponse.onSuccess(UserSuccessStatus._OK_GET_USER_INFO, userInfoResponseDto); } /** - * 회원가입시 닉네임 중복 확인을 한다. - * @return x + * 닉네임이 중복유무를 확인한다. + * @param request 유저 닉네임 + * @return void */ @PostMapping("/nickname/check") public ResponseEntity> checkNickname( @@ -53,25 +68,51 @@ public ResponseEntity> checkNickname( return ApiResponse.onSuccess(UserSuccessStatus._OK_NOT_DUPLICATED_NICKNAME); } + /** + * 리프레시 토큰을 통해 새로운 액세스 토큰과 리프레시 토큰을 발급받아 쿠키에 저장합니다. + * + * @param refreshToken 클라이언트로부터 전달받은 리프레시 토큰 (쿠키에서 추출) + * @param response 새로운 토큰을 클라이언트 쿠키에 저장하기 위한 HTTP 응답 객체 + * @return 성공 응답 + * @throws CustomException 리프레시 토큰이 없거나 유효하지 않을 경우 예외 발생 + */ + @PutMapping("/token/re-issue") + public ResponseEntity> reIssueToken( + @CookieValue(value = "refreshToken", required = false) String refreshToken, + HttpServletResponse response + ) { + + // AuthService를 통해 새 토큰 생성 + AuthTokenResponseDto authTokenResponseDto = userApplicationService.reIssueToken(refreshToken); + + // 새 토큰을 쿠키에 설정 + CookieUtil.setAuthCookies(response, authTokenResponseDto.accessToken(), authTokenResponseDto.refreshToken(), + authTokenResponseDto.accessTokenExpiration(), authTokenResponseDto.refreshTokenExpiration()); + + return ApiResponse.onSuccess(AuthSuccessStatus._OK_RE_ISSUE_TOKEN); + } /** * [2024.11.03 현재 미사용하는 기능] * [1인 1계정 처리 미사용과 과금부담으로 주석 처리] * 휴대폰에 6자리 인증코드를 보낸다. - * @return X + * @param request 휴대폰 번호 + * @return void */ -// @PostMapping("/send-code") +// @PostMapping("/code/send") // public ResponseEntity> sendAuthCode( // @Valid @RequestBody SendAuthCodeRequestDto request // ) { // userService.sendAuthCode(request); // return ApiResponse.onSuccess(UserSuccessStatus._OK_SEND_AUTH_CODE); // } + /** * 인증코드를 확인하여 휴대폰 인증을 진행한다. - * @return X + * @param request 클라이언트로부터 받은 휴대폰 번호와, 인증 코드 + * @return void */ -// @PostMapping("/verify-code") +// @PostMapping("/code/verify") // public ResponseEntity> verifyAuthCode( // @Valid @RequestBody VerifyAuthCodeRequestDto request // ) { diff --git a/src/main/java/kusitms/backend/auth/status/AuthErrorStatus.java b/src/main/java/kusitms/backend/user/status/AuthErrorStatus.java similarity index 97% rename from src/main/java/kusitms/backend/auth/status/AuthErrorStatus.java rename to src/main/java/kusitms/backend/user/status/AuthErrorStatus.java index 548b92a5..9b19acbf 100644 --- a/src/main/java/kusitms/backend/auth/status/AuthErrorStatus.java +++ b/src/main/java/kusitms/backend/user/status/AuthErrorStatus.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.status; +package kusitms.backend.user.status; import kusitms.backend.global.code.BaseErrorCode; import kusitms.backend.global.dto.ErrorReasonDto; @@ -9,6 +9,7 @@ @Getter @RequiredArgsConstructor public enum AuthErrorStatus implements BaseErrorCode { + _INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH-001", "유효하지 않은 토큰입니다."), _NOT_AUTHENTICATED(HttpStatus.UNAUTHORIZED, "AUTH-002", "사용자 인증에 실패했습니다."), _EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH-003", "만료된 토큰입니다."), diff --git a/src/main/java/kusitms/backend/auth/status/AuthSuccessStatus.java b/src/main/java/kusitms/backend/user/status/AuthSuccessStatus.java similarity index 95% rename from src/main/java/kusitms/backend/auth/status/AuthSuccessStatus.java rename to src/main/java/kusitms/backend/user/status/AuthSuccessStatus.java index be36599b..98192580 100644 --- a/src/main/java/kusitms/backend/auth/status/AuthSuccessStatus.java +++ b/src/main/java/kusitms/backend/user/status/AuthSuccessStatus.java @@ -1,4 +1,4 @@ -package kusitms.backend.auth.status; +package kusitms.backend.user.status; import kusitms.backend.global.code.BaseCode; import kusitms.backend.global.dto.ReasonDto; @@ -9,6 +9,7 @@ @Getter @AllArgsConstructor public enum AuthSuccessStatus implements BaseCode { + _OK_RE_ISSUE_TOKEN(HttpStatus.OK, "200", "토큰 재발급에 성공하였습니다."), ; @@ -34,4 +35,4 @@ public ReasonDto getReasonHttpStatus() { .message(message) .build(); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/user/status/UserErrorStatus.java b/src/main/java/kusitms/backend/user/status/UserErrorStatus.java index a70c619a..b755e371 100644 --- a/src/main/java/kusitms/backend/user/status/UserErrorStatus.java +++ b/src/main/java/kusitms/backend/user/status/UserErrorStatus.java @@ -12,13 +12,12 @@ public enum UserErrorStatus implements BaseErrorCode { _NOT_FOUND_USER(HttpStatus.NOT_FOUND, "USER-001", "해당 사용자를 찾을 수 없습니다."), _BAD_REQUEST_PROVIDER_STATUS_TYPE(HttpStatus.BAD_REQUEST, "USER-002", "잘못된 provider값입니다. (local, kakao, google, naver 중 하나로 입력해주세요.)"), - _BAD_REQUEST_PHONE_NUMBER_TYPE(HttpStatus.BAD_REQUEST, "USER-003", "잘못된 휴대폰 번호 형식입니다. 010-0000-0000 형식으로 입력해주세요."), - _EXPIRED_AUTH_CODE(HttpStatus.UNAUTHORIZED, "USER-004", "인증코드가 만료되었습니다. 인증코드를 재발급해주세요."), - _MISS_MATCH_AUTH_CODE(HttpStatus.BAD_REQUEST, "USER-005", "인증코드가 일치하지 않습니다."), - _EXISTING_USER_ACCOUNT_KAKAO(HttpStatus.FORBIDDEN, "USER-006", "이미 회원가입된 카카오 계정이 존재합니다."), - _EXISTING_USER_ACCOUNT_GOOGLE(HttpStatus.FORBIDDEN, "USER-007", "이미 회원가입된 구글 계정이 존재합니다."), - _EXISTING_USER_ACCOUNT_NAVER(HttpStatus.FORBIDDEN, "USER-008", "이미 회원가입된 네이버 계정이 존재합니다."), - _DUPLICATED_NICKNAME(HttpStatus.FORBIDDEN, "USER-009", "중복된 닉네임이 존재합니다. 다른 닉네임을 입력해주세요."); + _EXPIRED_AUTH_CODE(HttpStatus.UNAUTHORIZED, "USER-003", "인증코드가 만료되었습니다. 인증코드를 재발급해주세요."), + _MISS_MATCH_AUTH_CODE(HttpStatus.BAD_REQUEST, "USER-004", "인증코드가 일치하지 않습니다."), + _EXISTING_USER_ACCOUNT_KAKAO(HttpStatus.FORBIDDEN, "USER-005", "이미 회원가입된 카카오 계정이 존재합니다."), + _EXISTING_USER_ACCOUNT_GOOGLE(HttpStatus.FORBIDDEN, "USER-006", "이미 회원가입된 구글 계정이 존재합니다."), + _EXISTING_USER_ACCOUNT_NAVER(HttpStatus.FORBIDDEN, "USER-007", "이미 회원가입된 네이버 계정이 존재합니다."), + _DUPLICATED_NICKNAME(HttpStatus.FORBIDDEN, "USER-008", "중복된 닉네임이 존재합니다. 다른 닉네임을 입력해주세요."); private final HttpStatus httpStatus; private final String code; @@ -42,4 +41,4 @@ public ErrorReasonDto getReasonHttpStatus() { .message(message) .build(); } -} \ No newline at end of file +} diff --git a/src/main/java/kusitms/backend/user/status/UserSuccessStatus.java b/src/main/java/kusitms/backend/user/status/UserSuccessStatus.java index 9f09e906..d0c1f8bc 100644 --- a/src/main/java/kusitms/backend/user/status/UserSuccessStatus.java +++ b/src/main/java/kusitms/backend/user/status/UserSuccessStatus.java @@ -38,4 +38,4 @@ public ReasonDto getReasonHttpStatus() { .message(message) .build(); } -} \ No newline at end of file +} diff --git a/src/test/java/kusitms/backend/auth/AuthControllerTest.java b/src/test/java/kusitms/backend/auth/AuthControllerTest.java deleted file mode 100644 index 5a40e957..00000000 --- a/src/test/java/kusitms/backend/auth/AuthControllerTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package kusitms.backend.auth; - -import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; -import com.epages.restdocs.apispec.ResourceSnippetParameters; -import jakarta.servlet.http.Cookie; -import kusitms.backend.auth.application.AuthService; -import kusitms.backend.auth.dto.response.TokenResponseDto; -import kusitms.backend.auth.presentation.AuthController; -import kusitms.backend.configuration.ControllerTestConfig; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; -import org.springframework.test.web.servlet.ResultActions; - -import static com.epages.restdocs.apispec.ResourceDocumentation.resource; -import static org.mockito.ArgumentMatchers.anyString; -import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; -import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@WebMvcTest(AuthController.class) -public class AuthControllerTest extends ControllerTestConfig { - - @MockBean - private AuthService authService; - - @Test - @DisplayName("토큰 재발급을 한다.") - public void reIssueToken() throws Exception { - - Mockito.when(authService.reIssueToken(anyString())) - .thenReturn(new TokenResponseDto("newAccessToken", "newRefreshToken", 3600L, 7200L)); - - // when - ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.put("/api/v1/token/re-issue") - .cookie(new Cookie("refreshToken", "test")) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)); - - // then - resultActions - .andExpect(status().isOk()) - .andExpect(jsonPath("$.isSuccess").value(true)) - .andExpect(jsonPath("$.code").value(200)) - .andExpect(jsonPath("$.message").value("토큰 재발급에 성공하였습니다.")) - .andDo(MockMvcRestDocumentationWrapper.document("token/re-issue", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - resource( - ResourceSnippetParameters.builder() - .tag("Auth") - .description("리프레시 토큰을 통해 액세스 토큰을 재발급합니다.") - .responseFields( - fieldWithPath("isSuccess").description("성공 여부"), - fieldWithPath("code").description("응답 코드"), - fieldWithPath("message").description("응답 메시지") - ) - .build() - ), - requestCookies( - cookieWithName("refreshToken").description("리프레시 토큰") - ) - )); - } -} diff --git a/src/test/java/kusitms/backend/user/UserControllerTest.java b/src/test/java/kusitms/backend/user/UserEntityControllerTest.java similarity index 77% rename from src/test/java/kusitms/backend/user/UserControllerTest.java rename to src/test/java/kusitms/backend/user/UserEntityControllerTest.java index 866987b9..d548fb0b 100644 --- a/src/test/java/kusitms/backend/user/UserControllerTest.java +++ b/src/test/java/kusitms/backend/user/UserEntityControllerTest.java @@ -6,9 +6,10 @@ import jakarta.servlet.http.Cookie; import kusitms.backend.configuration.ControllerTestConfig; import kusitms.backend.user.application.UserApplicationService; -import kusitms.backend.user.dto.request.CheckNicknameRequestDto; -import kusitms.backend.user.dto.request.SignUpRequestDto; -import kusitms.backend.user.dto.response.UserInfoResponseDto; +import kusitms.backend.user.application.dto.request.CheckNicknameRequestDto; +import kusitms.backend.user.application.dto.request.SignUpRequestDto; +import kusitms.backend.user.application.dto.response.AuthTokenResponseDto; +import kusitms.backend.user.application.dto.response.UserInfoResponseDto; import kusitms.backend.user.presentation.UserController; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,7 +32,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(UserController.class) -public class UserControllerTest extends ControllerTestConfig { +public class UserEntityControllerTest extends ControllerTestConfig { @MockBean private UserApplicationService userApplicationService; @@ -50,7 +51,7 @@ public void checkNickname() throws Exception { Mockito.doNothing().when(userApplicationService).checkNickname(any(CheckNicknameRequestDto.class)); // when - ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/nickname/check") + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/user/nickname/check") .content(checkNicknameJsonRequest) .cookie(new Cookie("registerToken", "test")) .contentType(MediaType.APPLICATION_JSON) @@ -95,10 +96,11 @@ public void signUpUser() throws Exception { "nickname" : "유저 닉네임" } """; - Mockito.doNothing().when(userApplicationService).signupUser(anyString(), any(SignUpRequestDto.class)); + Mockito.when(userApplicationService.signupUser(anyString(), any(SignUpRequestDto.class))) + .thenReturn(new AuthTokenResponseDto("newAccessToken", "newRefreshToken", 3600L, 7200L));; // when - ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/signup") + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.post("/api/v1/user/signup") .cookie(new Cookie("registerToken", "test")) .content(signUpRequestDto) .contentType(MediaType.APPLICATION_JSON) @@ -145,7 +147,7 @@ public void getUserInfo() throws Exception { .thenReturn(userInfoResponseDto); // when - ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/user-info") + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.get("/api/v1/user/info") .cookie(new Cookie("accessToken", "test")) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)); @@ -182,4 +184,44 @@ public void getUserInfo() throws Exception { ) )); } + + @Test + @DisplayName("토큰 재발급을 한다.") + public void reIssueToken() throws Exception { + + Mockito.when(userApplicationService.reIssueToken(anyString())) + .thenReturn(new AuthTokenResponseDto("newAccessToken", "newRefreshToken", 3600L, 7200L)); + + // when + ResultActions resultActions = this.mockMvc.perform(RestDocumentationRequestBuilders.put("/api/v1/user/token/re-issue") + .cookie(new Cookie("refreshToken", "test")) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)); + + // then + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.isSuccess").value(true)) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.message").value("토큰 재발급에 성공하였습니다.")) + .andDo(MockMvcRestDocumentationWrapper.document("token/re-issue", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + resource( + ResourceSnippetParameters.builder() + .tag("User") + .description("리프레시 토큰을 통해 액세스 토큰을 재발급합니다.") + .responseFields( + fieldWithPath("isSuccess").description("성공 여부"), + fieldWithPath("code").description("응답 코드"), + fieldWithPath("message").description("응답 메시지") + ) + .build() + ), + requestCookies( + cookieWithName("refreshToken").description("리프레시 토큰") + ) + )); + } + } \ No newline at end of file diff --git a/task ':build'/generated/sources/annotationProcessor/java/main/kusitms/backend/user/domain/entity/QUser.java b/task ':build'/generated/sources/annotationProcessor/java/main/kusitms/backend/user/infra/jpa/entity/QUserEntity.java similarity index 67% rename from task ':build'/generated/sources/annotationProcessor/java/main/kusitms/backend/user/domain/entity/QUser.java rename to task ':build'/generated/sources/annotationProcessor/java/main/kusitms/backend/user/infra/jpa/entity/QUserEntity.java index eebfe541..a7914646 100644 --- a/task ':build'/generated/sources/annotationProcessor/java/main/kusitms/backend/user/domain/entity/QUser.java +++ b/task ':build'/generated/sources/annotationProcessor/java/main/kusitms/backend/user/infra/jpa/entity/QUserEntity.java @@ -1,4 +1,4 @@ -package kusitms.backend.user.domain.entity; +package kusitms.backend.user.infra.jpa.entity; import static com.querydsl.core.types.PathMetadataFactory.*; @@ -10,14 +10,14 @@ /** - * QUser is a Querydsl query type for User + * QUserEntity is a Querydsl query type for UserEntity */ @Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QUser extends EntityPathBase { +public class QUserEntity extends EntityPathBase { - private static final long serialVersionUID = -392524671L; + private static final long serialVersionUID = 784583091L; - public static final QUser user = new QUser("user"); + public static final QUserEntity userEntity = new QUserEntity("userEntity"); public final kusitms.backend.global.domain.QBaseTimeEntity _super = new kusitms.backend.global.domain.QBaseTimeEntity(this); @@ -37,16 +37,16 @@ public class QUser extends EntityPathBase { //inherited public final DateTimePath updatedDate = _super.updatedDate; - public QUser(String variable) { - super(User.class, forVariable(variable)); + public QUserEntity(String variable) { + super(UserEntity.class, forVariable(variable)); } - public QUser(Path path) { + public QUserEntity(Path path) { super(path.getType(), path.getMetadata()); } - public QUser(PathMetadata metadata) { - super(User.class, metadata); + public QUserEntity(PathMetadata metadata) { + super(UserEntity.class, metadata); } }