Skip to content

Commit e9291e6

Browse files
committed
feat: 구글 소셜 로그인 서비스 로직 구현
1 parent b790cfb commit e9291e6

2 files changed

Lines changed: 128 additions & 3 deletions

File tree

src/main/java/com/back/web7_9_codecrete_be/domain/auth/service/AuthService.java

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.web7_9_codecrete_be.domain.auth.service;
22

3+
import com.back.web7_9_codecrete_be.domain.auth.dto.google.GoogleUserInfo;
34
import com.back.web7_9_codecrete_be.domain.auth.dto.kakao.KakaoUserInfo;
45
import com.back.web7_9_codecrete_be.domain.auth.dto.request.LoginRequest;
56
import com.back.web7_9_codecrete_be.domain.auth.dto.request.SignupRequest;
@@ -8,6 +9,7 @@
89
import com.back.web7_9_codecrete_be.domain.users.entity.SocialType;
910
import com.back.web7_9_codecrete_be.domain.users.entity.User;
1011
import com.back.web7_9_codecrete_be.domain.users.repository.UserRepository;
12+
import com.back.web7_9_codecrete_be.domain.users.util.NicknameGenerator;
1113
import com.back.web7_9_codecrete_be.global.error.code.AuthErrorCode;
1214
import com.back.web7_9_codecrete_be.global.error.code.UserErrorCode;
1315
import com.back.web7_9_codecrete_be.global.error.exception.BusinessException;
@@ -28,6 +30,8 @@ public class AuthService {
2830
private final EmailService emailService;
2931
private final TokenService tokenService;
3032
private final KakaoOAuthService kakaoOAuthService;
33+
private final GoogleOAuthService googleOAuthService;
34+
private final NicknameGenerator nicknameGenerator;
3135

3236
// 회원가입
3337
public void signUp(SignupRequest req) {
@@ -165,7 +169,7 @@ public LoginResponse kakaoLogin(String code) {
165169

166170
private User registerKakaoUser(KakaoUserInfo info) {
167171

168-
String nickname = info.getNickname();
172+
String nickname = nicknameGenerator.generate();
169173
if (userRepository.existsByNickname(nickname)) {
170174
nickname = nickname + "_" + System.currentTimeMillis();
171175
}
@@ -183,8 +187,55 @@ private User registerKakaoUser(KakaoUserInfo info) {
183187
return userRepository.save(user);
184188
}
185189

190+
@Transactional
186191
public LoginResponse googleLogin(String code) {
187-
// TODO: 구글 인가 코드 → 사용자 정보 → 로그인 처리
188-
throw new UnsupportedOperationException("구글 로그인 미구현");
192+
193+
// 1. 인가 코드 → 구글 Access Token
194+
String googleAccessToken = googleOAuthService.getAccessToken(code);
195+
196+
// 2. Access Token → 사용자 정보
197+
GoogleUserInfo googleUserInfo = googleOAuthService.getUserInfo(googleAccessToken);
198+
199+
if (googleUserInfo.getEmail() == null) {
200+
throw new BusinessException(AuthErrorCode.SOCIAL_EMAIL_NOT_PROVIDED);
201+
}
202+
203+
// 3. 소셜 ID 기준 사용자 조회
204+
User user = userRepository
205+
.findBySocialTypeAndSocialId(
206+
SocialType.GOOGLE,
207+
googleUserInfo.getSocialId()
208+
)
209+
.orElseGet(() -> registerGoogleUser(googleUserInfo));
210+
211+
// 4. 탈퇴 사용자 체크
212+
if (user.getIsDeleted()) {
213+
throw new BusinessException(UserErrorCode.USER_DELETED);
214+
}
215+
216+
// 5. 토큰 발급
217+
tokenService.issueTokens(user);
218+
219+
return new LoginResponse(user.getId(), user.getNickname());
220+
}
221+
222+
private User registerGoogleUser(GoogleUserInfo info) {
223+
224+
String nickname = nicknameGenerator.generate();
225+
if (userRepository.existsByNickname(nickname)) {
226+
nickname = nickname + "_" + System.currentTimeMillis();
227+
}
228+
229+
User user = User.builder()
230+
.email(info.getEmail())
231+
.nickname(nickname)
232+
.password(null)
233+
.birth(null)
234+
.profileImage(info.getProfileImageUrl())
235+
.socialType(SocialType.GOOGLE)
236+
.socialId(info.getSocialId())
237+
.build();
238+
239+
return userRepository.save(user);
189240
}
190241
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.back.web7_9_codecrete_be.domain.auth.service;
2+
3+
import com.back.web7_9_codecrete_be.domain.auth.dto.google.GoogleTokenResponse;
4+
import com.back.web7_9_codecrete_be.domain.auth.dto.google.GoogleUserInfo;
5+
import com.back.web7_9_codecrete_be.domain.auth.dto.google.GoogleUserResponse;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.beans.factory.annotation.Value;
8+
import org.springframework.http.*;
9+
import org.springframework.stereotype.Service;
10+
import org.springframework.util.LinkedMultiValueMap;
11+
import org.springframework.util.MultiValueMap;
12+
import org.springframework.web.client.RestTemplate;
13+
14+
@Service
15+
@RequiredArgsConstructor
16+
public class GoogleOAuthService {
17+
18+
@Value("${oauth.google.client-id}")
19+
private String clientId;
20+
21+
@Value("${oauth.google.client-secret}")
22+
private String clientSecret;
23+
24+
@Value("${oauth.google.redirect-uri}")
25+
private String redirectUri;
26+
27+
private static final String TOKEN_URL = "https://oauth2.googleapis.com/token";
28+
private static final String USER_INFO_URL = "https://www.googleapis.com/oauth2/v2/userinfo";
29+
30+
private final RestTemplate restTemplate = new RestTemplate();
31+
32+
// 인가 코드 → 액세스 토큰
33+
public String getAccessToken(String code) {
34+
HttpHeaders headers = new HttpHeaders();
35+
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
36+
37+
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
38+
params.add("grant_type", "authorization_code");
39+
params.add("client_id", clientId);
40+
params.add("client_secret", clientSecret);
41+
params.add("redirect_uri", redirectUri);
42+
params.add("code", code);
43+
44+
HttpEntity<MultiValueMap<String, String>> request =
45+
new HttpEntity<>(params, headers);
46+
47+
ResponseEntity<GoogleTokenResponse> response =
48+
restTemplate.postForEntity(
49+
TOKEN_URL,
50+
request,
51+
GoogleTokenResponse.class
52+
);
53+
54+
return response.getBody().getAccessToken();
55+
}
56+
57+
// 액세스 토큰 → 구글 사용자 정보
58+
public GoogleUserInfo getUserInfo(String accessToken) {
59+
HttpHeaders headers = new HttpHeaders();
60+
headers.setBearerAuth(accessToken);
61+
62+
HttpEntity<Void> request = new HttpEntity<>(headers);
63+
64+
ResponseEntity<GoogleUserResponse> response =
65+
restTemplate.exchange(
66+
USER_INFO_URL,
67+
HttpMethod.GET,
68+
request,
69+
GoogleUserResponse.class
70+
);
71+
72+
return response.getBody().toUserInfo();
73+
}
74+
}

0 commit comments

Comments
 (0)