diff --git a/src/main/java/com/wayble/server/auth/controller/AuthController.java b/src/main/java/com/wayble/server/auth/controller/AuthController.java new file mode 100644 index 00000000..67d27083 --- /dev/null +++ b/src/main/java/com/wayble/server/auth/controller/AuthController.java @@ -0,0 +1,111 @@ +package com.wayble.server.auth.controller; + +import com.wayble.server.auth.service.AuthService; +import com.wayble.server.auth.service.KakaoLoginService; +import com.wayble.server.common.exception.ApplicationException; +import com.wayble.server.common.response.CommonResponse; +import com.wayble.server.user.dto.KakaoLoginRequestDto; +import com.wayble.server.user.dto.KakaoLoginResponseDto; +import com.wayble.server.user.dto.UserLoginRequestDto; +import com.wayble.server.auth.dto.TokenResponseDto; +import com.wayble.server.user.exception.UserErrorCase; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/v1/auth") +@RequiredArgsConstructor +@Validated +public class AuthController { + + private final AuthService authService; + + private final KakaoLoginService kakaoLoginService; + + @PostMapping("/login/basic") + @Operation( + summary = "유저 로그인", + description = "이메일+비밀번호 로그인 및 JWT 발급" + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "로그인 성공", + content = @Content(schema = @Schema(implementation = com.wayble.server.common.response.CommonResponse.class))), + @ApiResponse(responseCode = "400", description = "아이디 혹은 비밀번호가 잘못됨", + content = @Content(schema = @Schema(implementation = com.wayble.server.common.response.CommonResponse.class))) + }) + public CommonResponse login(@RequestBody @Valid UserLoginRequestDto req) { + TokenResponseDto tokenDto = authService.login(req); + return CommonResponse.success(tokenDto); + } + + @PostMapping("/login/kakao") + @Operation(summary = "카카오 소셜 로그인", description = "카카오 AccessToken으로 소셜 로그인을 수행합니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "로그인 성공"), + @ApiResponse(responseCode = "401", description = "카카오 인증 실패"), + @ApiResponse(responseCode = "500", description = "서버 오류") + }) + public CommonResponse kakaoLogin( + @RequestBody @Valid KakaoLoginRequestDto request + ) { + KakaoLoginResponseDto response = kakaoLoginService.kakaoLogin(request); + return CommonResponse.success(response); + } + + @PostMapping("/reissue") + @Operation( + summary = "AccessToken 재발급", + description = "클라이언트의 accessToken 만료 시, 유효한 refreshToken으로 새로운 accessToken 및 refreshToken을 재발급합니다." + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "토큰 재발급 성공", + content = @Content(schema = @Schema(implementation = TokenResponseDto.class))), + @ApiResponse(responseCode = "400", description = "refreshToken이 유효하지 않음", + content = @Content(schema = @Schema(implementation = com.wayble.server.common.response.CommonResponse.class))) + }) + public CommonResponse reissue( + @Parameter(description = "재발급용 refreshToken", required = true) + @RequestParam String refreshToken + ) { + TokenResponseDto tokens = authService.reissue(refreshToken); + return CommonResponse.success(tokens); + } + + @PostMapping("/logout") + @Operation( + summary = "유저 로그아웃", + description = "로그아웃 처리(서버에 저장된 refreshToken을 삭제합니다)." + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "로그아웃 성공"), + @ApiResponse(responseCode = "401", description = "유효하지 않은 accessToken") + }) + public CommonResponse logout( + @Parameter( + description = "사용자 인증용 accessToken (Bearer {token} 형태)", + required = true, + example = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + ) + @RequestHeader("Authorization") String accessToken + ) { + if (accessToken == null || !accessToken.startsWith("Bearer ")) { + throw new ApplicationException(UserErrorCase.INVALID_CREDENTIALS); + } + String token = accessToken.replace("Bearer ", ""); + if (token.isEmpty()) { + throw new ApplicationException(UserErrorCase.INVALID_CREDENTIALS); + } + Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + authService.logout(userId); + return CommonResponse.success("로그아웃에 성공하였습니다."); + } +} diff --git a/src/main/java/com/wayble/server/user/dto/token/TokenResponseDto.java b/src/main/java/com/wayble/server/auth/dto/TokenResponseDto.java similarity index 64% rename from src/main/java/com/wayble/server/user/dto/token/TokenResponseDto.java rename to src/main/java/com/wayble/server/auth/dto/TokenResponseDto.java index f006ecc8..9db3a864 100644 --- a/src/main/java/com/wayble/server/user/dto/token/TokenResponseDto.java +++ b/src/main/java/com/wayble/server/auth/dto/TokenResponseDto.java @@ -1,3 +1,3 @@ -package com.wayble.server.user.dto.token; +package com.wayble.server.auth.dto; public record TokenResponseDto(String accessToken, String refreshToken) {} \ No newline at end of file diff --git a/src/main/java/com/wayble/server/user/entity/RefreshToken.java b/src/main/java/com/wayble/server/auth/enttiy/RefreshToken.java similarity index 94% rename from src/main/java/com/wayble/server/user/entity/RefreshToken.java rename to src/main/java/com/wayble/server/auth/enttiy/RefreshToken.java index 5fdecb6e..283025a0 100644 --- a/src/main/java/com/wayble/server/user/entity/RefreshToken.java +++ b/src/main/java/com/wayble/server/auth/enttiy/RefreshToken.java @@ -1,4 +1,4 @@ -package com.wayble.server.user.entity; +package com.wayble.server.auth.enttiy; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java b/src/main/java/com/wayble/server/auth/repository/RefreshTokenRepository.java similarity index 80% rename from src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java rename to src/main/java/com/wayble/server/auth/repository/RefreshTokenRepository.java index f23e2252..03d70326 100644 --- a/src/main/java/com/wayble/server/user/repository/RefreshTokenRepository.java +++ b/src/main/java/com/wayble/server/auth/repository/RefreshTokenRepository.java @@ -1,6 +1,6 @@ -package com.wayble.server.user.repository; +package com.wayble.server.auth.repository; -import com.wayble.server.user.entity.RefreshToken; +import com.wayble.server.auth.enttiy.RefreshToken; import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/wayble/server/user/service/auth/AuthService.java b/src/main/java/com/wayble/server/auth/service/AuthService.java similarity index 93% rename from src/main/java/com/wayble/server/user/service/auth/AuthService.java rename to src/main/java/com/wayble/server/auth/service/AuthService.java index e73f338e..82973d44 100644 --- a/src/main/java/com/wayble/server/user/service/auth/AuthService.java +++ b/src/main/java/com/wayble/server/auth/service/AuthService.java @@ -1,13 +1,13 @@ -package com.wayble.server.user.service.auth; +package com.wayble.server.auth.service; import com.wayble.server.common.config.security.jwt.JwtTokenProvider; import com.wayble.server.common.exception.ApplicationException; import com.wayble.server.user.dto.UserLoginRequestDto; -import com.wayble.server.user.dto.token.TokenResponseDto; -import com.wayble.server.user.entity.RefreshToken; +import com.wayble.server.auth.dto.TokenResponseDto; +import com.wayble.server.auth.enttiy.RefreshToken; import com.wayble.server.user.entity.User; import com.wayble.server.user.exception.UserErrorCase; -import com.wayble.server.user.repository.RefreshTokenRepository; +import com.wayble.server.auth.repository.RefreshTokenRepository; import com.wayble.server.user.repository.UserRepository; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/wayble/server/user/service/auth/KakaoLoginService.java b/src/main/java/com/wayble/server/auth/service/KakaoLoginService.java similarity index 98% rename from src/main/java/com/wayble/server/user/service/auth/KakaoLoginService.java rename to src/main/java/com/wayble/server/auth/service/KakaoLoginService.java index aefb321b..922766b3 100644 --- a/src/main/java/com/wayble/server/user/service/auth/KakaoLoginService.java +++ b/src/main/java/com/wayble/server/auth/service/KakaoLoginService.java @@ -1,4 +1,4 @@ -package com.wayble.server.user.service.auth; +package com.wayble.server.auth.service; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/main/java/com/wayble/server/common/config/SecurityConfig.java b/src/main/java/com/wayble/server/common/config/SecurityConfig.java index 23ff6b25..62a873c0 100644 --- a/src/main/java/com/wayble/server/common/config/SecurityConfig.java +++ b/src/main/java/com/wayble/server/common/config/SecurityConfig.java @@ -38,6 +38,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/api/v1/users/login", "/api/v1/users/reissue", "/api/v1/users/logout", + "/api/v1/auth/**", "/swagger-ui/**", "/v3/api-docs/**", "/", diff --git a/src/main/java/com/wayble/server/user/controller/KakaoLoginController.java b/src/main/java/com/wayble/server/user/controller/KakaoLoginController.java deleted file mode 100644 index 43d3f0b3..00000000 --- a/src/main/java/com/wayble/server/user/controller/KakaoLoginController.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.wayble.server.user.controller; - -import com.wayble.server.common.response.CommonResponse; -import com.wayble.server.user.dto.KakaoLoginRequestDto; -import com.wayble.server.user.dto.KakaoLoginResponseDto; -import com.wayble.server.user.service.auth.KakaoLoginService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -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; - -@RestController -@RequestMapping("/api/v1/users/login") -@RequiredArgsConstructor -public class KakaoLoginController { - - private final KakaoLoginService kakaoLoginService; - - @PostMapping("/kakao") - @Operation(summary = "카카오 소셜 로그인", description = "카카오 AccessToken으로 소셜 로그인을 수행합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "로그인 성공"), - @ApiResponse(responseCode = "401", description = "카카오 인증 실패"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) - public CommonResponse kakaoLogin( - @RequestBody @Valid KakaoLoginRequestDto request - ) { - KakaoLoginResponseDto response = kakaoLoginService.kakaoLogin(request); - return CommonResponse.success(response); - } -} \ No newline at end of file diff --git a/src/main/java/com/wayble/server/user/controller/UserController.java b/src/main/java/com/wayble/server/user/controller/UserController.java index 8d38d29d..8f4115b4 100644 --- a/src/main/java/com/wayble/server/user/controller/UserController.java +++ b/src/main/java/com/wayble/server/user/controller/UserController.java @@ -5,15 +5,12 @@ import com.wayble.server.common.response.CommonResponse; import com.wayble.server.user.dto.UserInfoRegisterRequestDto; import com.wayble.server.user.dto.UserInfoUpdateRequestDto; -import com.wayble.server.user.dto.UserLoginRequestDto; import com.wayble.server.user.dto.UserRegisterRequestDto; -import com.wayble.server.user.dto.token.TokenResponseDto; import com.wayble.server.user.exception.UserErrorCase; import com.wayble.server.user.service.UserInfoService; import com.wayble.server.user.service.UserService; -import com.wayble.server.user.service.auth.AuthService; +import com.wayble.server.auth.service.AuthService; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -32,8 +29,7 @@ public class UserController { private final UserService userService; - private final AuthService authService; - private final JwtTokenProvider jwtProvider; + private final UserInfoService userInfoService; @PostMapping("/signup") @@ -52,72 +48,6 @@ public CommonResponse signup(@RequestBody @Valid UserRegisterRequestDto return CommonResponse.success("회원가입 성공"); } - @PostMapping("/login") - @Operation( - summary = "유저 로그인", - description = "이메일+비밀번호 로그인 및 JWT 발급" - ) - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "로그인 성공", - content = @Content(schema = @Schema(implementation = com.wayble.server.common.response.CommonResponse.class))), - @ApiResponse(responseCode = "400", description = "아이디 혹은 비밀번호가 잘못됨", - content = @Content(schema = @Schema(implementation = com.wayble.server.common.response.CommonResponse.class))) - }) - public CommonResponse login(@RequestBody @Valid UserLoginRequestDto req) { - TokenResponseDto tokenDto = authService.login(req); - return CommonResponse.success(tokenDto); - } - - @PostMapping("/reissue") - @Operation( - summary = "AccessToken 재발급", - description = "클라이언트의 accessToken 만료 시, 유효한 refreshToken으로 새로운 accessToken 및 refreshToken을 재발급합니다." - - - ) - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "토큰 재발급 성공", - content = @Content(schema = @Schema(implementation = com.wayble.server.user.dto.token.TokenResponseDto.class))), - @ApiResponse(responseCode = "400", description = "refreshToken이 유효하지 않음", - content = @Content(schema = @Schema(implementation = com.wayble.server.common.response.CommonResponse.class))) - }) - public CommonResponse reissue( - @Parameter(description = "재발급용 refreshToken", required = true) - @RequestParam String refreshToken - ) { - TokenResponseDto tokens = authService.reissue(refreshToken); - return CommonResponse.success(tokens); - } - - @PostMapping("/logout") - @Operation( - summary = "유저 로그아웃", - description = "로그아웃 처리(서버에 저장된 refreshToken을 삭제합니다)." - ) - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "로그아웃 성공"), - @ApiResponse(responseCode = "401", description = "유효하지 않은 accessToken") - }) - public CommonResponse logout( - @Parameter( - description = "사용자 인증용 accessToken (Bearer {token} 형태)", - required = true, - example = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - ) - @RequestHeader("Authorization") String accessToken - ) { - if (accessToken == null || !accessToken.startsWith("Bearer ")) { - throw new ApplicationException(UserErrorCase.INVALID_CREDENTIALS); - } - String token = accessToken.replace("Bearer ", ""); - if (token.isEmpty()) { - throw new ApplicationException(UserErrorCase.INVALID_CREDENTIALS); - } - Long userId = jwtProvider.getUserId(token); - authService.logout(userId); - return CommonResponse.success("로그아웃에 성공하였습니다."); - } - @PostMapping("/info") @Operation(summary = "내 정보 등록", description = "유저의 상세 정보를 최초 1회 등록합니다.") @ApiResponses({