From 27c09b2fe1af8d7927b1311438c52fb04a31fe3e Mon Sep 17 00:00:00 2001 From: gaeunee2 Date: Sun, 17 May 2026 17:54:52 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EA=B5=AC=EA=B8=80=20=EC=86=8C?= =?UTF-8?q?=EC=85=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/AuthController.java | 23 ---- .../auth/dto/google/GoogleTokenResponse.java | 18 --- .../auth/dto/google/GoogleUserResponse.java | 23 ---- .../auth/dto/request/GoogleLoginRequest.java | 12 -- .../auth/dto/response/GoogleUserInfo.java | 23 ---- .../auth/dto/response/LoginResponse.java | 11 +- .../auth/provider/GoogleOAuthClient.java | 105 ------------------ .../domain/auth/service/AuthService.java | 46 -------- .../domain/auth/service/JwtTokenProvider.java | 19 ---- .../domain/user/entity/OAuthProvider.java | 3 +- src/main/resources/application.yaml | 7 -- 11 files changed, 2 insertions(+), 288 deletions(-) delete mode 100644 src/main/java/com/proovy/domain/auth/dto/google/GoogleTokenResponse.java delete mode 100644 src/main/java/com/proovy/domain/auth/dto/google/GoogleUserResponse.java delete mode 100644 src/main/java/com/proovy/domain/auth/dto/request/GoogleLoginRequest.java delete mode 100644 src/main/java/com/proovy/domain/auth/dto/response/GoogleUserInfo.java delete mode 100644 src/main/java/com/proovy/domain/auth/provider/GoogleOAuthClient.java diff --git a/src/main/java/com/proovy/domain/auth/controller/AuthController.java b/src/main/java/com/proovy/domain/auth/controller/AuthController.java index 5450462..cce82d4 100644 --- a/src/main/java/com/proovy/domain/auth/controller/AuthController.java +++ b/src/main/java/com/proovy/domain/auth/controller/AuthController.java @@ -1,6 +1,5 @@ package com.proovy.domain.auth.controller; -import com.proovy.domain.auth.dto.request.GoogleLoginRequest; import com.proovy.domain.auth.dto.request.KakaoLoginRequest; import com.proovy.domain.auth.dto.request.LogoutRequest; import com.proovy.domain.auth.dto.request.NaverLoginRequest; @@ -91,28 +90,6 @@ public ResponseEntity> naverLogin( return ResponseEntity.ok(ApiResponse.success(message, response)); } - @PostMapping("/login/google") - @Operation( - operationId = "04_googleLogin", - summary = "구글 소셜 로그인", - description = "구글 인가 코드로 로그인합니다. 신규 유저는 회원가입 토큰을 반환합니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "로그인 성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Redirect URI 불일치 (AUTH4001)"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "유효하지 않은 인증 코드 (AUTH4011)"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "502", description = "구글 서버 오류 (AUTH5023)") - }) - public ResponseEntity> googleLogin( - @Valid @RequestBody GoogleLoginRequest request - ) { - LoginResponse response = authService.googleLogin(request); - - String message = "SIGNUP_REQUIRED".equals(response.loginType()) - ? "추가 정보 입력이 필요합니다." - : "로그인에 성공했습니다."; - - return ResponseEntity.ok(ApiResponse.success(message, response)); - } @PostMapping("/signup/complete") @Operation( diff --git a/src/main/java/com/proovy/domain/auth/dto/google/GoogleTokenResponse.java b/src/main/java/com/proovy/domain/auth/dto/google/GoogleTokenResponse.java deleted file mode 100644 index 24c888d..0000000 --- a/src/main/java/com/proovy/domain/auth/dto/google/GoogleTokenResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.proovy.domain.auth.dto.google; - -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonNaming; - -/** - * 구글 토큰 발급 응답 - * POST https://oauth2.googleapis.com/token - */ -@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) -public record GoogleTokenResponse( - String tokenType, // "Bearer" - String accessToken, // 사용자 액세스 토큰 - Integer expiresIn, // 액세스 토큰 만료 시간 (초) - String refreshToken, // 사용자 리프레시 토큰 (첫 인증 시에만 반환) - String scope, // 인증된 사용자 정보 조회 권한 - String idToken // JWT 형식의 ID 토큰 (openid scope 사용 시) -) {} diff --git a/src/main/java/com/proovy/domain/auth/dto/google/GoogleUserResponse.java b/src/main/java/com/proovy/domain/auth/dto/google/GoogleUserResponse.java deleted file mode 100644 index a88934b..0000000 --- a/src/main/java/com/proovy/domain/auth/dto/google/GoogleUserResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.proovy.domain.auth.dto.google; - -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonNaming; - -/** - * 구글 사용자 정보 응답 - * GET https://www.googleapis.com/oauth2/v2/userinfo - * - * 구글에서 받아오는 정보: 고유 ID, 이메일, 이름 - * 휴대폰 번호는 제공하지 않음 (회원가입 시 직접 입력) - */ -@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) -public record GoogleUserResponse( - String id, // 구글 고유 사용자 ID (providerUserId) - String email, // 이메일 - Boolean verifiedEmail, // 이메일 인증 여부 - String name, // 전체 이름 (null 가능) - String givenName, // 이름 (선택) - String familyName, // 성 (선택) - String picture, // 프로필 이미지 URL (고정 로고) - String locale // 언어 설정 (ko, en 등) -) {} diff --git a/src/main/java/com/proovy/domain/auth/dto/request/GoogleLoginRequest.java b/src/main/java/com/proovy/domain/auth/dto/request/GoogleLoginRequest.java deleted file mode 100644 index 99ed214..0000000 --- a/src/main/java/com/proovy/domain/auth/dto/request/GoogleLoginRequest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.proovy.domain.auth.dto.request; - -import jakarta.validation.constraints.NotBlank; - -/** - * 구글 로그인 요청 - * redirectUri는 서버 설정값 사용 - */ -public record GoogleLoginRequest( - @NotBlank(message = "인증 코드는 필수입니다") - String authorizationCode -) {} diff --git a/src/main/java/com/proovy/domain/auth/dto/response/GoogleUserInfo.java b/src/main/java/com/proovy/domain/auth/dto/response/GoogleUserInfo.java deleted file mode 100644 index 19ec8a7..0000000 --- a/src/main/java/com/proovy/domain/auth/dto/response/GoogleUserInfo.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.proovy.domain.auth.dto.response; - -import com.proovy.domain.auth.dto.google.GoogleUserResponse; -import lombok.Builder; - -/** - * 프론트엔드 전달용 구글 사용자 정보 - * 고유 ID, 이메일, 이름 포함 (휴대폰 번호는 회원가입 시 직접 입력받음) - */ -@Builder -public record GoogleUserInfo( - String id, // 구글 고유 사용자 ID (signupToken에 포함되어 회원가입 시 providerUserId로 저장) - String email, // 이메일 - String name // 이름 (null 가능) -) { - public static GoogleUserInfo from(GoogleUserResponse response) { - return GoogleUserInfo.builder() - .id(response.id()) - .email(response.email()) - .name(response.name()) - .build(); - } -} diff --git a/src/main/java/com/proovy/domain/auth/dto/response/LoginResponse.java b/src/main/java/com/proovy/domain/auth/dto/response/LoginResponse.java index bbbf0ed..ab6cb83 100644 --- a/src/main/java/com/proovy/domain/auth/dto/response/LoginResponse.java +++ b/src/main/java/com/proovy/domain/auth/dto/response/LoginResponse.java @@ -9,8 +9,7 @@ public record LoginResponse( TokenDto token, // 기존 유저인 경우 JWT 토큰 String signupToken, // 신규 유저인 경우 회원가입용 임시 토큰 KakaoUserInfo kakaoInfo, // 신규 유저인 경우 카카오에서 받은 정보 - NaverUserInfo naverInfo, // 네이버 신규 유저 - GoogleUserInfo googleInfo // 구글 신규 유저 + NaverUserInfo naverInfo // 네이버 신규 유저 ) { public static LoginResponse login(UserDto user, TokenDto token) { return LoginResponse.builder() @@ -38,12 +37,4 @@ public static LoginResponse signupRequired(String signupToken, NaverUserInfo nav .build(); } - // 구글 신규 유저 - public static LoginResponse signupRequired(String signupToken, GoogleUserInfo googleInfo) { - return LoginResponse.builder() - .loginType("SIGNUP_REQUIRED") - .signupToken(signupToken) - .googleInfo(googleInfo) - .build(); - } } \ No newline at end of file diff --git a/src/main/java/com/proovy/domain/auth/provider/GoogleOAuthClient.java b/src/main/java/com/proovy/domain/auth/provider/GoogleOAuthClient.java deleted file mode 100644 index 1ea210d..0000000 --- a/src/main/java/com/proovy/domain/auth/provider/GoogleOAuthClient.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.proovy.domain.auth.provider; - -import com.proovy.domain.auth.dto.google.GoogleTokenResponse; -import com.proovy.domain.auth.dto.google.GoogleUserResponse; -import com.proovy.global.exception.BusinessException; -import com.proovy.global.response.ErrorCode; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatusCode; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClientResponseException; -import reactor.core.publisher.Mono; - -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; - -@Slf4j -@Component -@RequiredArgsConstructor -public class GoogleOAuthClient { - - private final WebClient webClient; - - @Value("${oauth.google.client-id}") - private String clientId; - - @Value("${oauth.google.client-secret}") - private String clientSecret; - - @Value("${oauth.google.redirect-uri}") - private String redirectUri; - - @Value("${oauth.google.token-uri}") - private String tokenUri; - - @Value("${oauth.google.user-info-uri}") - private String userInfoUri; - - /** - * 인가 코드로 액세스 토큰 발급 - * redirectUri는 서버 설정값 사용 - */ - public GoogleTokenResponse getAccessToken(String authorizationCode) { - // 구글 인가 코드는 '/'를 포함하므로 URL 디코딩 필요 (4%2F... -> 4/...) - String decodedCode = URLDecoder.decode(authorizationCode, StandardCharsets.UTF_8); - - try { - return webClient.post() - .uri(tokenUri) - .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .body(BodyInserters.fromFormData("grant_type", "authorization_code") - .with("client_id", clientId) - .with("redirect_uri", redirectUri) - .with("code", decodedCode) - .with("client_secret", clientSecret)) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, response -> - response.bodyToMono(String.class) - .flatMap(body -> { - log.error("구글 토큰 발급 실패 (4xx): {}", body); - if (body.contains("redirect_uri_mismatch")) { - return Mono.error(new BusinessException(ErrorCode.AUTH4001)); - } - return Mono.error(new BusinessException(ErrorCode.AUTH4011)); - })) - .onStatus(HttpStatusCode::is5xxServerError, response -> - Mono.error(new BusinessException(ErrorCode.AUTH5023))) - .bodyToMono(GoogleTokenResponse.class) - .block(); - } catch (WebClientResponseException e) { - log.error("구글 토큰 발급 API 호출 실패", e); - throw new BusinessException(ErrorCode.AUTH5023); - } - } - - /** - * 액세스 토큰으로 사용자 정보 조회 - */ - public GoogleUserResponse getUserInfo(String accessToken) { - try { - return webClient.get() - .uri(userInfoUri) - .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken) - .retrieve() - .onStatus(HttpStatusCode::is4xxClientError, response -> - response.bodyToMono(String.class) - .flatMap(body -> { - log.error("구글 사용자 정보 조회 실패 (4xx): {}", body); - return Mono.error(new BusinessException(ErrorCode.AUTH4013)); - })) - .onStatus(HttpStatusCode::is5xxServerError, response -> - Mono.error(new BusinessException(ErrorCode.AUTH5023))) - .bodyToMono(GoogleUserResponse.class) - .block(); - } catch (WebClientResponseException e) { - log.error("구글 사용자 정보 조회 API 호출 실패", e); - throw new BusinessException(ErrorCode.AUTH5023); - } - } -} diff --git a/src/main/java/com/proovy/domain/auth/service/AuthService.java b/src/main/java/com/proovy/domain/auth/service/AuthService.java index a0cfcca..8839e4f 100644 --- a/src/main/java/com/proovy/domain/auth/service/AuthService.java +++ b/src/main/java/com/proovy/domain/auth/service/AuthService.java @@ -1,12 +1,9 @@ package com.proovy.domain.auth.service; -import com.proovy.domain.auth.dto.google.GoogleTokenResponse; -import com.proovy.domain.auth.dto.google.GoogleUserResponse; import com.proovy.domain.auth.dto.kakao.KakaoTokenResponse; import com.proovy.domain.auth.dto.kakao.KakaoUserResponse; import com.proovy.domain.auth.dto.naver.NaverTokenResponse; import com.proovy.domain.auth.dto.naver.NaverUserResponse; -import com.proovy.domain.auth.dto.request.GoogleLoginRequest; import com.proovy.domain.auth.dto.request.KakaoLoginRequest; import com.proovy.domain.auth.dto.request.NaverLoginRequest; import com.proovy.domain.auth.dto.request.SignupCompleteRequest; @@ -14,7 +11,6 @@ import com.proovy.domain.auth.entity.NaverState; import io.jsonwebtoken.Claims; import com.proovy.domain.auth.entity.RefreshToken; -import com.proovy.domain.auth.provider.GoogleOAuthClient; import com.proovy.domain.auth.provider.KakaoOAuthClient; import com.proovy.domain.auth.provider.NaverOAuthClient; import com.proovy.domain.auth.repository.NaverStateRepository; @@ -46,7 +42,6 @@ public class AuthService { private final KakaoOAuthClient kakaoClient; private final NaverOAuthClient naverClient; - private final GoogleOAuthClient googleClient; private final NaverStateRepository naverStateRepository; private final UserRepository userRepository; private final JwtTokenProvider jwtTokenProvider; @@ -163,47 +158,6 @@ public LoginResponse naverLogin(@Valid NaverLoginRequest request) { } } - /** - * 구글 로그인 처리 - */ - @Transactional - public LoginResponse googleLogin(GoogleLoginRequest request) { - // 1. 구글 액세스 토큰 발급 - GoogleTokenResponse googleToken = googleClient.getAccessToken( - request.authorizationCode() - ); - log.info("구글 토큰 발급 성공, expires_in: {}", googleToken.expiresIn()); - - // 2. 구글 사용자 정보 조회 - GoogleUserResponse googleUser = googleClient.getUserInfo(googleToken.accessToken()); - log.info("구글 사용자 정보 조회 성공, id: {}", googleUser.id()); - - // 3. 기존 유저 조회 (OAuthProvider enum 사용) - String providerUserId = googleUser.id(); - Optional existingUser = userRepository - .findByProviderAndProviderUserId(OAuthProvider.GOOGLE, providerUserId); - - // 4. 분기 처리 - if (existingUser.isPresent()) { - // 기존 유저: JWT 발급 - User user = existingUser.get(); - TokenDto tokens = jwtTokenProvider.generateTokens(user.getId()); - - // Refresh Token Redis 저장 - saveRefreshToken(user.getId(), tokens.refreshToken()); - - log.info("기존 유저 로그인 성공 (구글), userId: {}", user.getId()); - return LoginResponse.login(UserDto.from(user), tokens); - - } else { - // 신규 유저: signupToken 발급 - GoogleUserInfo googleInfo = GoogleUserInfo.from(googleUser); - String signupToken = jwtTokenProvider.generateSignupToken(googleInfo); - - log.info("신규 유저 감지 (구글), 회원가입 필요, googleId: {}", googleUser.id()); - return LoginResponse.signupRequired(signupToken, googleInfo); - } - } /** * 회원가입 완료 처리 diff --git a/src/main/java/com/proovy/domain/auth/service/JwtTokenProvider.java b/src/main/java/com/proovy/domain/auth/service/JwtTokenProvider.java index 57433bb..95cc90b 100644 --- a/src/main/java/com/proovy/domain/auth/service/JwtTokenProvider.java +++ b/src/main/java/com/proovy/domain/auth/service/JwtTokenProvider.java @@ -1,6 +1,5 @@ package com.proovy.domain.auth.service; -import com.proovy.domain.auth.dto.response.GoogleUserInfo; import com.proovy.domain.auth.dto.response.KakaoUserInfo; import com.proovy.domain.auth.dto.response.NaverUserInfo; import com.proovy.domain.auth.dto.response.TokenDto; @@ -107,24 +106,6 @@ public String generateSignupToken(NaverUserInfo naverInfo) { .compact(); } - /** - * 회원가입용 임시 토큰 생성 (구글 정보 포함) - * 구글은 이름도 포함 (null 가능) - */ - public String generateSignupToken(GoogleUserInfo googleInfo) { - Date now = new Date(); - - return Jwts.builder() - .subject(googleInfo.id()) - .claim("type", "signup") - .claim("provider", "GOOGLE") - .claim("email", googleInfo.email()) - .claim("name", googleInfo.name()) - .issuedAt(now) - .expiration(new Date(now.getTime() + signupTokenExpiration)) - .signWith(secretKey) - .compact(); - } /** * 토큰에서 userId 추출 diff --git a/src/main/java/com/proovy/domain/user/entity/OAuthProvider.java b/src/main/java/com/proovy/domain/user/entity/OAuthProvider.java index 396295f..e9a583b 100644 --- a/src/main/java/com/proovy/domain/user/entity/OAuthProvider.java +++ b/src/main/java/com/proovy/domain/user/entity/OAuthProvider.java @@ -2,8 +2,7 @@ public enum OAuthProvider { KAKAO("/images/logo/kakao.png"), - NAVER("/images/logo/naver.png"), - GOOGLE("/images/logo/google.png"); + NAVER("/images/logo/naver.png"); private final String logoUrl; diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 90ae58f..44dac04 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -95,13 +95,6 @@ oauth: # state 유효 시간 (초) state-ttl: 300 - google: - client-id: ${GOOGLE_CLIENT_ID} - client-secret: ${GOOGLE_CLIENT_SECRET} - redirect-uri: ${GOOGLE_REDIRECT_URI:http://localhost:5173/oauth/google/callback} - # 구글 API 엔드포인트 - token-uri: https://oauth2.googleapis.com/token - user-info-uri: https://www.googleapis.com/oauth2/v2/userinfo # =============================== # JWT 설정 (서비스 자체 토큰)