구글 OAuth2.0을 이용한 소셜 로그인 구현
구글에서 제공하는 OAuth2.0을 이용해야 하기에, 관련 로그인 기능 사용 신청을 위해 구글 계정 로그인후 구글 클라우드 플랫폼 콘솔로 이동한다.
https://console.cloud.google.com/
Google 클라우드 플랫폼
로그인 Google 클라우드 플랫폼으로 이동
accounts.google.com
구글 클라우드 플랫폼에서 새로운 프로젝트를 생성한다.
프로젝트 생성 완료이후, API 및 서비스 탭의 OAuth 동의 화면으로 이동하여 필요한 설정을 진행한다.
OAuth 동의 화면에서 앱 이름, 이메일등 필수 값을 입력후 '저장 후 계속' 버튼을 클릭한다.
API 및 서비스 - 사용자 인증 정보 탭으로 이동하여 OAuth2.0 클라이언트를 생성한다.
리디렉션 URI는 구글 로그인 화면에서 계정 로그인후 호출할 대상 서버의 주소이며, 구글로부터 데이터를 전달 받을 내 서버의 주소를 입력하면된다. 여기까지 마무리하고 나면 클라이언트 ID가 발급된다.
구글 OAuth2.0 로그인은 위 시퀀스 다이어그램의 흐름대로 진행되게 된다.
1. 사용자의 요청에 의해 구글로그인을 진행후, 구글은 서버로 Authorization Code를 전달.
2. Authorization Code를 전달받은 서버는 해당 코드를 이용해서 구글 서버로부터 AccessToken를 획득.
3. 서버는 전달받은 AccessToken을 이용해서 최종적으로 Google API를 호출(여기서는 회원 정보 조회)
각각의 내용을 따라 진행해보자.
1. 사용자의 요청에 의해 구글로그인을 진행후, 구글은 서버로 Authorization Code를 전달
아래와 같은 URL 포맷을 통해 구글 로그인 화면으로 이동할 수 있으며,
여기서 로그인 이후 방금 입력해 놓은 리다이렉션 주소로 구글이 Token을 전달하게 된다.
https://accounts.google.com/o/oauth2/auth?
client_id={클라이언트ID}&redirect_uri={리다이렉션URL}
&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
2. Authorization Code를 전달받은 서버는 해당 코드를 이용해서 구글 서버로부터 AccessToken를 획득
유저의 구글 로그인 시도 이후 서버로 전달된 Authorization Code를 이용해서 서버는 다시 구글 인증 서버와 토큰 교환을 요청한다.
https://oauth2.googleapis.com/token (구글 토큰 교환 서버)
3. 서버는 전달받은 AccessToken을 이용해서 최종적으로 Google API를 호출
1,2,3의 과정을 포함하는 Service Layer Code
@RestController
@RequestMapping("/test")
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@GetMapping("/test")
public void authGoogleCode(@RequestParam String code) throws IOException {
authService.loginByGoogle(code);
}
}
@Service
@RequiredArgsConstructor
public class AuthService {
@Value("${spring.security.oauth2.client.registration.google.client-id}")
private String googleClientId;
@Value("${spring.security.oauth2.client.registration.google.client-secret}")
private String googleClientSecret;
@Value("${spring.security.oauth2.client.registration.google.redirect-uri}")
private String googleRedirectUrl;
private ObjectMapper objectMapper;
private RestTemplate restTemplate;
@PostConstruct
void init() {
objectMapper = new ObjectMapper();
restTemplate = new RestTemplate();
}
public void loginByGoogle(String authorizationCode) throws IOException {
// 1. AuthorizationToken 과 AccessToken 교환
GoogleTokenResponse googleToken = getGoogleToken(authorizationCode);
// 2. AccessToken 이용 사용자 정보 획득
GoogleUserInfo googleUserInfo = getGoogleUserInfo(googleToken.getAccessToken());
System.out.println();
// todo 유저 정보가 DB에 있을 경우 로그인 진행
// todo 유저 정보가 없을 경우 회원 가입 진행
}
/** Authorization Token 이용 Google Token 발급 */
private GoogleTokenResponse getGoogleToken(String authorizationCode)
throws JsonProcessingException {
GoogleTokenRequest googleTokenRequest = GoogleTokenRequest
.create(authorizationCode, googleClientId, googleClientSecret, googleRedirectUrl);
URI getTokenUri = UriComponentsBuilder
.fromUriString("https://oauth2.googleapis.com")
.path("/token").encode().build().toUri();
ResponseEntity<String> googleResponse =
restTemplate.postForEntity(getTokenUri, googleTokenRequest, String.class);
return objectMapper.readValue(googleResponse.getBody(), GoogleTokenResponse.class);
}
/** Token 이용 사용자 정보 조회 */
private GoogleUserInfo getGoogleUserInfo(String accessToken) throws JsonProcessingException {
URI getTokenInfoUri = UriComponentsBuilder
.fromUriString("https://www.googleapis.com")
.path("/oauth2/v2/userinfo")
.queryParam("access_token", accessToken).encode().build().toUri();
ResponseEntity<String> googleTokenInfoResponse =
restTemplate.getForEntity(getTokenInfoUri, String.class);
return objectMapper.readValue(googleTokenInfoResponse.getBody(), GoogleUserInfo.class);
}
}
'Spring' 카테고리의 다른 글
[Spring] 서비스 운영간 발생한 DB Connection Closed 이슈 (0) | 2023.08.30 |
---|---|
[Spirng, JPA] object references an unsaved transient instance - save the transient instance before flushing (0) | 2023.08.16 |
[JPA]연관관계 - 다대다(N:M) (0) | 2023.08.09 |
[JPA]연관관계 - 일대일 관계 (0) | 2023.07.27 |
[JPA] 연관관계 조회 방식별(Fetch, Lazy) 성능 차이 테스트 (0) | 2023.07.25 |