본문 바로가기
Project/모면

[Spring Boot] Security 없이 OAuth2로 Google 로그인 구현, 유저 정보 얻기

by 독서왕뼝아리 2023. 3. 27.

세션 저장, Spring Security 코드가 난무한 클론코딩 글들이 너무 많아 그냥 내가 쓰는 글이다... 
 
 

 

웹 서버 애플리케이션용 OAuth 2.0 사용     |  Authorization  |  Google Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 웹 서버 애플리케이션용 OAuth 2.0 사용 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분

developers.google.com

 
 

GCP 설정 후

"http://accounts.google.com/o/oauth2/v2/auth" 엔드포인트client_id, redirect_uri, response_type, scope 4개의 필수 파라미터와 함께 GET 요청을 보내야 승인 매개변수(code)를 받아 올 수 있다. 
 
 
scope 이리저리 만져보니 GCP에서 따로 승인 허가를 하지 않으면 '액세스 거부됨'하고 진행이 막히게 된다. 기본 예제에선 email과 profile로 작성한다고 한다.
 
 
파라미터 작업이 완성된 URL은 다음과 같다. 나는 이 부분은 프론트에서 작업할 거라 따로 구현하지 않았다.

"https://accounts.google.com/o/oauth2/v2/auth\
        ?client_id=(클라이언트 아이디) \
        &redirect_uri=http://localhost:8080/api/oauth2/callback/google \
        &response_type=code \
        &scope=profile";

 
 
서버를 가동시키고 위 URL에 접속하면 계정 선택 페이지가 나오게 되는데

 
계정 선택을 하면 아까 설정한 "승인된 리디렉션 URI" (http://localhost:8080/api/oauth2/callback/google)로 리디렉션 된다. 
프로젝트에 GET 매핑하지 않았다면 404 에러가 발생하니 얼른 구현하시길!
 
 
이때 code가 파라미터로 전해진다. 일단은 간단하게 매핑해주었다.

//...RequestMapping("/api/oauth2/")...

@GetMapping("callback/google")
public ResponseEntity<String> successGoogleLogin(@RequestParam("code") String accessCode){
    return oAuthService.getGoogleAccessToken(accessCode);
}

 
 
 

참고로 GCP의 리디렉션 URI와 Application의 URI가 정확하게 일치해야 오류가 나지 않는다. Bad Request: redirect_uri_mismatch 오류가 난다면 이 부분을 확인하자.
 
 
 
 

access_token을 발급받으려면 "http://oauth2.googleapis.com/token" 엔드포인트client_id, client_secret, code, grant_type, redirect_uri 5개의 필수 파라미터POST 요청을 보내야 한다. 나는 post를 못보고 get으로 계속 보내면서 삽질했다.
 
 

@Service
@RequiredArgsConstructor
public class OAuthService {

    private final String GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
    @Value("${oauth2.google.client-id}")
    private String GOOGLE_CLIENT_ID;
    @Value("${oauth2.google.client-secret}")
    private String GOOGLE_CLIENT_SECRET;
    @Value("${oauth2.google.redirect-uri}")
    private String LOGIN_REDIRECT_URL;

    @Autowired
    private final MemberRepository memberRepository;

    public ResponseEntity<String> getGoogleAccessToken(String accessCode) {

        RestTemplate restTemplate=new RestTemplate();
        Map<String, String> params = new HashMap<>();
        
        params.put("code", accessCode);
        params.put("client_id", GOOGLE_CLIENT_ID);
        params.put("client_secret", GOOGLE_CLIENT_SECRET);
        params.put("redirect_uri", LOGIN_REDIRECT_URL);
        params.put("grant_type", "authorization_code");

        ResponseEntity<String> responseEntity=restTemplate.postForEntity(GOOGLE_TOKEN_URL, params,String.class);

        if(responseEntity.getStatusCode() == HttpStatus.OK){
            return responseEntity;
        }
        return null;
    }
}

받아온 code를 사용해 POST 요청을 보내는 기능이다. 이때도 redirect_uri는 아까 설정한 "승인된 리디렉션 URI"이다. grant_type은 기본값이면서 왜 써야하는지 모르겠다.
 
 
 
다시 서버를 구동시켜 위 작업을 처음부터 다시 해보자.

야호&nbsp;⸜(*ˊᗜˋ*)⸝

정상적으로 access_token이 발급된 것을 확인할 수 있다!! 
근데 어피치가 보고 있는 저 부분, 'id_token'이 뭘까?
 

여기까지 흐름은

 


 

ID 토큰 payload

 

OpenID Connect  |  Authentication  |  Google Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English 의견 보내기 OpenID Connect 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Google의 OAuth 2.0 AP

developers.google.com

 
바로 정체는..
 
 

야호&nbsp;⸜(*ˊᗜˋ*)⸝

계정의 정보가 담겨있는 JWT 토큰이다. RS256으로 암호화되어 있으니 프로젝트에서 디코딩 해서 사용하면 된다. 'sub'이 Google Open Authentication에서 제공하는 계정 유일 ID 이다! 그 외에도 이름, 사진, 이메일 등 기본 정보를 얻을 수 있다.
 
 
이 프로젝트에선 Google 액세스 토큰을 사용하지 않을 거지만 유저 정보를 알기 위해 이 작업을 했다. 디코딩해서 DB 저장하는 건 다음 시간에 ∠( ᐛ 」∠)_
 
 
백 개의 블로그보다 한 개의 공식 문서 최고!