https://github.com/jinwoo-Bae/spring-react-google-oauth2
Googgle Oauth2 를 사용한 로그인 시나리오입니다.
클라이언트는 리액트를, 서버는 스프링부트를 사용하여 구현하였습니다.
결과는 다음과 같습니다.
로그인 페이지에서 Google 계정으로 로그인을 하면 마이페이지로 리다이렉트 됩니다.
저는 클라이언트를 담당하였고, 리액트를 사용해서 구현하였습니다.
먼저 Oauth2 를 사용하려면 Oauth2 서버에 대한 애플리케이션을 식별하는 인증 자격 증명이 있어야합니다.
저는 하단의 문서를 참고하여 인증 자격 증명을 만들었습니다.
https://developers.google.com/identity/sign-in/web/sign-in#create_authorization_credentials
- Credentials 페이지에 들어갑니다.
- 자격 증명 만들기 > OAuth 클라이언트 ID 를 클릭합니다.
- 웹 응용 프로그램 유형을 선택합니다.
- OAuth 2.0 클라이언트의 이름을 지정하고 만들기 를 클릭합니다.
처음엔 react-google-login
모듈을 사용해서 구현하고자 하였습니다.
하지만 해당 모듈은 새로운 Goggle Identity Services JS 라이브러리를 호환하지 않았습니다. 따라서 새로운 라이브러리 호환을 위해서 react-google-login
모듈의 마이그레이션이 필요하다는 아래와 같은 에러가 발생하였습니다.
Will the plugin be providing the support and migration to the new standard google identity based login that returns a CredentialResponse rather than a userToken as google is "discontinuing the Google Sign-In JavaScript Platform Library for web".
해당 이슈는 깃허브 이슈에 open 되어있었습니다.
새로운 Goggle Identity Services JS 라이브러리와 이전 과의 차이점, 그리고 마이그레이션하는 방법에 대한 문서는 다음과 같습니다. 참고하시길 바랍니다.
따라서 react-google-login
모듈을 사용할 수 없다고 판단하여서 다른 방법을 찾았습니다.
gapi.auth2
모듈 사용하기react-google-login
대신에 구글 공식 사이트에서 제안하는 gapi.auth2
모듈을 사용해서 구글 로그인을 구현하였습니다.
하단의 외부 script를 불러온 다음, 구글 클라이언트 API를 사용하여 로그인 버튼에 대한 핸들러와 스타일링을 수행할 수 있습니다.
<script src="https://accounts.google.com/gsi/client" async defer></script>
구글 로그인 컴포넌트는 gapi.auth2
모듈을 사용하여 다음과 같이 구현하였습니다.
로그인 구글 자바스크립트 문서를 참고하였습니다.
완성된 컴포넌트는 Git을 확인해보시길 바랍니다.
window.google.accounts.id.initialize
메서드로 인증 자격 증명의 클라이언트 아이디와 로그인이 완료된 후 호출될 콜백을 설정해주었습니다.
window.google.accounts.id.renderButton
메서드로 로그인 버튼이 실제로 위치할 위치의 부모 요소와, 버튼의 스타일에 대한 option들을 설정해주었습니다.
import { useRef } from 'react';
import useScript from '../hooks/useScript';
// https://github.com/anthonyjgrove/react-google-login/issues/502
// https://developers.google.com/identity/gsi/web/reference/js-reference#CredentialResponse
export default function GoogleLogin({
onGoogleSignIn = () => {},
text = 'signin_with',
}) {
const googleSignInButton = useRef(null);
useScript('https://accounts.google.com/gsi/client', () => {
// https://developers.google.com/identity/gsi/web/reference/js-reference#google.accounts.id.initialize
window.google.accounts.id.initialize({
client_id: process.env.REACT_APP_GOOGLE_CLIENT_ID,
callback: onGoogleSignIn,
});
// https://developers.google.com/identity/gsi/web/reference/js-reference#google.accounts.id.renderButton
window.google.accounts.id.renderButton(
googleSignInButton.current,
{ theme: 'filled_blue', size: 'large', text, width: '250' }, // customization attributes
);
});
return <div ref={googleSignInButton}></div>;
}
로그인 페이지는 다음과 같이, GoogleLogin
컴포넌트를 사용하여 구글 로그인이 가능하도록 하였습니다.
onGoogleSignIn
핸들러에서 구글 로그인 후 credential 토큰을 받아서 우리 서버에게 토큰을 전달해주는 postLoginToken API 요청을 보냅니다.
서버는 받은 토큰값으로 로그인 처리리를 수행한 다음, 인증 정보가 담긴 토큰을 쿠키에 담아 클라이언트에게 전달합니다.
받은 쿠키는 쿠키를 보낸 origin에게 API 요청을 보내는 경우에 자동으로 Header에 담겨서 보내지게 됩니다. 따라서 추가적으로 쿠키를 요청 Header에 담거나 할 필요가 없습니다.
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import GoogleLogin from '../components/GoogleLogin';
import Nav from '../components/Nav';
import { postLoginToken } from '../api/postLoginToken';
export default function Login({ isLogin, setIsLogin }) {
const navigate = useNavigate();
// https://stackoverflow.com/questions/49819183/react-what-is-the-best-way-to-handle-login-and-authentication
const onGoogleSignIn = async res => {
const { credential } = res;
const result = await postLoginToken(credential, setIsLogin);
setIsLogin(result);
};
useEffect(() => {
if (!isLogin) return;
navigate('/mypage');
}, [isLogin]);
return (
<div>
<h1>Goggle Login</h1>
<Nav />
<GoogleLogin onGoogleSignIn={onGoogleSignIn} text="로그인" />
</div>
);
}
마이페이지에서는 로그인한 사용자 정보를 받아옵니다.
위에서 언급했듯이 서버에서 로그인 토큰 정보가 담긴 쿠키
를 이미 받았으므로 서버에게 사용자 정보를 요청하는 API 를 보낼 때 따로 쿠키를 담아주는 처리는 필요가 없습니다.
구글 소셜 로그인 공부하는데 큰 도움이 됐습니다!! 감사합니다!!🙇♂️🙇♂️