구글 로그인 API 스프링부트 OAuth 2.0 - 2. 구현해보기
이전 포스팅에 이어 스프링 부트와 구글 Oauth API 로그인 연동을 구현해본다.
2022.12.17 - [슬기로운 자바 개발자 생활/스프링 및 자바웹 서비스] - 스프링부트 구글로그인 API 구현 OAuth 2.0 - 1. 구글 설정 하기
소스를 첨부하니 혹시나 포스팅의 결과와 다르다면 참고하시기 바란다.
Over View
기능은 상단히 간단하다.
링크를 건 구글 설정만 잘했다면 큰 어려움 없이 1시간 내로 구현을 할 수 있을 거라 예상한다.
1. 개발환경
인텔리J 기반. 스프링 부트니까. 이클립스 툴로 구성해도 차이가 없다.
스프링 부트 2.7.7-SNAPSHOT 버전
JDK 1.8 이상
메이븐 JSON
JSP 나 뷰를 이용해서 구현하지 않았다. 단순히. REST API 정도로 만도 충분히 활용할 수 있을듯하다.
2. 로그인 프로세스 설명
우리가 구축할 스프링부트 레드망고 서비스와 구글 간의 통신을 정리
3. 소스 설정 및 구현
application.properties 파일에 지난 시간에 구글에서 발급받은 클라이언트 ID와 보안 키 그리고 리다이렉션 URI 등을 등록한다.
google.auth.url=https://oauth2.googleapis.com
google.login.url=https://accounts.google.com
google.redirect.url=http://localhost:8080/login/oauth_google_check
google.client.id=구글에서 발급받은 ID
google.secret= 구글에서 발급받은 보안키
GoogleOAuthReqest.java
구글에게 발급받은 클라이언트 ID와 리다이렉션 URI 보안키 등을 보내어 토큰을 받을 VO 객체 클래스를 정의한다.
위 표의 3번 작업에서 사용될 객체다.
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class GoogleOAuthRequest {
private String redirectUri;
private String clientId;
private String clientSecret;
private String code;
private String responseType;
private String scope;
private String accessType;
private String grantType;
private String state;
private String includeGrantedScopes;
private String loginHint;
private String prompt;
}
GoogleLoginResponse.java
구글에게서 토큰을 받게 된다.
토큰을 저장할 Vo 객체를 하나 더 만든다. 위 표에서 4, 5번에 사용될 객체다.
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class GoogleLoginResponse {
private String access_token; // 애플리케이션이 Google API 요청을 승인하기 위해 보내는 토큰
private String expires_in; // Access Token의 남은 수명
private String refreshToken; // 새 액세스 토큰을 얻는 데 사용할 수 있는 토큰
private String scope;
private String token_type; // 반환된 토큰 유형(Bearer 고정)
private String id_token;
}
ApiRestController.java 라는 컨트롤러 자바 클래스를 만든다.
메서드는 두개를 만든다.
- getGoogleAuthUr 단순히 브라우저에서 call 하면 구글 로그인 페이지로 연결. 구글에서 보내온 주소로 리다이렉션
- oauth_google_check 구글에게 토큰을 요청해서 받고, 받은 토큰을 다시 보내 유저 정보를 얻는 기능을 한다.
ApiRestController.java 의 전체 소스를 보자.
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
@Slf4j
@RestController
public class ApiRestController {
@Value("${google.auth.url}")
private String googleAuthUrl;
@Value("${google.login.url}")
private String googleLoginUrl;
@Value("${google.client.id}")
private String googleClientId;
@Value("${google.redirect.url}")
private String googleRedirectUrl;
@Value("${google.secret}")
private String googleClientSecret;
// 구글 로그인창 호출
// http://localhost:8080/login/getGoogleAuthUrl
@GetMapping(value = "/login/getGoogleAuthUrl")
public ResponseEntity<?> getGoogleAuthUrl(HttpServletRequest request) throws Exception {
String reqUrl = googleLoginUrl + "/o/oauth2/v2/auth?client_id=" + googleClientId + "&redirect_uri=" + googleRedirectUrl
+ "&response_type=code&scope=email%20profile%20openid&access_type=offline";
log.info("myLog-LoginUrl : {}",googleLoginUrl);
log.info("myLog-ClientId : {}",googleClientId);
log.info("myLog-RedirectUrl : {}",googleRedirectUrl);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(reqUrl));
//1.reqUrl 구글로그인 창을 띄우고, 로그인 후 /login/oauth_google_check 으로 리다이렉션하게 한다.
return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
}
// 구글에서 리다이렉션
@GetMapping(value = "/login/oauth_google_check")
public String oauth_google_check(HttpServletRequest request,
@RequestParam(value = "code") String authCode,
HttpServletResponse response) throws Exception{
//2.구글에 등록된 레드망고 설정정보를 보내어 약속된 토큰을 받위한 객체 생성
GoogleOAuthRequest googleOAuthRequest = GoogleOAuthRequest
.builder()
.clientId(googleClientId)
.clientSecret(googleClientSecret)
.code(authCode)
.redirectUri(googleRedirectUrl)
.grantType("authorization_code")
.build();
RestTemplate restTemplate = new RestTemplate();
//3.토큰요청을 한다.
ResponseEntity<GoogleLoginResponse> apiResponse = restTemplate.postForEntity(googleAuthUrl + "/token", googleOAuthRequest, GoogleLoginResponse.class);
//4.받은 토큰을 토큰객체에 저장
GoogleLoginResponse googleLoginResponse = apiResponse.getBody();
log.info("responseBody {}",googleLoginResponse.toString());
String googleToken = googleLoginResponse.getId_token();
//5.받은 토큰을 구글에 보내 유저정보를 얻는다.
String requestUrl = UriComponentsBuilder.fromHttpUrl(googleAuthUrl + "/tokeninfo").queryParam("id_token",googleToken).toUriString();
//6.허가된 토큰의 유저정보를 결과로 받는다.
String resultJson = restTemplate.getForObject(requestUrl, String.class);
return resultJson;
}
}
힌트 : 토큰이란... 잠시동안 어떤 권한을 갖는 것을 의미한다.
소스 설명
- 1. application.properties에 등록한 구글 변수들을 받아왔다. 롬복으로 저장
- 2. 서버가 실행이 된 후, 브라우저에서 http://localhost:8080/login/getGoogleAuthUrl 를 입력한다.
- 3. ApiRestController 안의 getGoogleAuthUrl 로 진입하여 구글 OAth 주소를 만들어 구글 로그인 창으로 리다이렉션 시킨다.
- 4. 유저가 구글 로그인을 하고 확인을 클릭하면, 미리약속된 레드망고 서비스의 리다이렉션 주소 /login/oauth_google_check 즉, ApiRestController 의 oauth_google_check 메서드로 진입 하게 된다. 로그인이 정상이라면 authCode를 갖고 진입.
- 5. 소스상 3번 이며, oauth_google_check에서는 authCode와 application.properties에 정의된 변수들을 갖고 GoogleOAuthRequest 객체를 생성한다. 이 객체를 구글에 보내고 결과로 토큰을 받는다.
- 6. 받은 토큰을 갖고 다시 구글에 유저정보를 요청한다. 소스 5번 부분
- 7. 소스상 6번 부분으로 토큰에 해당하는 유저의 정보를 받게 되며 구글과의 통신 작업은 끝이 난다.
실행 및 결과
1. 호출
2. 구글 로그인으로 리다이렉션
3. 로그인 후, 리다이렉션의 결과
정리 및 기타
RestTemplate 을 사용했지만, Spring 5부터는 WebClient을 사용하는 것을 추천한다. RestTemplate는 동기식이니까...
UriComponentsBuilder는 클래스명에서 유추할 수 있듯이, Uri를 좀 더 편하게 만들어주는 클래스다.
UriComponentsBuilder 쓴 부분은 String으로 만들어서 던져도 관계는 없다.
String requestUrl = UriComponentsBuilder.fromHttpUrl(googleAuthUrl + "/tokeninfo").queryParam("id_token",googleToken).toUriString();
GoogleOAuthReqest.java, GoogleLoginResponse.java
두 객체는 구글에서 리턴되거나 구글에서 받는 변수와 동일하게 셋팅을 해야 한다. 딱히 가공을 안 했다.
소스 상 6번 부터는 여러 가지 상황별로 나뉠 수가 있다.
레드망고 DB에 넣을 수도 있고, 다른 페이지를 보여줘서 유저 정보를 추가적으로 받을 수도 있을 것이다. 예) 배송정보
최종 오는 정보에는 구글 로그인한 유저의 사진 URL도 있다.
이번 포스팅은 핵심 OAth 개념을 잡고, 간단하게 예제를 만들어봤다.
글이 도움이 되셨다면 공감 클릭 부탁합니다.
'슬기로운 자바 개발자 생활 > 스프링 및 자바웹 서비스' 카테고리의 다른 글
JSP page request, response (0) | 2023.01.14 |
---|---|
JSP page 지시자 errorPage, isErrorPage 사용법 (0) | 2023.01.14 |
스프링부트에서 jsp사용하기 (1) | 2022.12.17 |
스프링부트 구글로그인 API 구현 OAuth 2.0 - 1. 구글 설정 하기 (2) | 2022.12.17 |
Spring Profile 활용 Application.properties (0) | 2022.12.15 |
댓글