๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

React

[ React / Next ] Web Google Login ๊ธฐ๋Šฅ ๊ตฌํ˜„ (gsi/client)

ํšŒ์‚ฌ์—์„œ Next๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” Web์˜ Google Login ์ง€์›์„ ์œ„ํ•ด ์›น์šฉ Google ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ด์„œ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ์šฉํ•˜๋˜ react-google-login ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ

 

๋” ์ด์ƒ ๊ตฌ๊ธ€์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ผ์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

 

 

 

๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋‹ค๊ฐ€ ์•„๋ž˜์˜ ๊ตฌ๊ธ€ ๊ฐœ๋ฐœ์ž ํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ Google Identity Service(GSI)๋ฅผ ์ด์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

 

 

 

๊ณต์‹ ๋ฌธ์„œ ๋งํฌ

๊ตฌ๊ธ€ ๊ฐœ๋ฐœ์ž ํŽ˜์ด์ง€ Authentication  - ์›น์šฉ Google ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ

 

 


 

 

 

Google ๋กœ๊ทธ์ธ ํŠน์ง•

 

- Google ๊ณ„์ •์œผ๋กœ ์›น ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

 

- ์‚ฌ์šฉ์ž๋Š” Google ๊ณ„์ •์— ๋กœ๊ทธ์ธํ•˜๊ณ  ๋™์˜ํ•˜๋ฉฐ ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ํ”Œ๋žซํผ๊ณผ ๊ณต์œ ํ•œ๋‹ค.

 

- Google ๊ณ„์ •์„ ์ด์šฉํ•œ ์„œ๋น„์Šค ๊ฐ€์ž…์ด๋ž€, Google ๊ณ„์ • ์†Œ์œ ์ž์˜ ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ํ”Œ๋žซํผ๊ณผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•œ ๋™์˜๋ฅผ ์–ป๋Š” ๋‹จ๊ณ„์ด๋‹ค.

 

- ์ผ๋ฐ˜์ ์œผ๋กœ ์ด ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋น„์Šค์— ์ƒˆ ๊ณ„์ •์ด ์ƒ์„ฑ๋˜์ง€๋งŒ ํ•„์ˆ˜์ ์ด์ง€๋Š” ์•Š๋‹ค.

 

- ๋กœ๊ทธ์ธ์ด๋ž€, ์ด๋ฏธ Google ๊ณ„์ •์„ ์ด์šฉํ•˜์—ฌ ์„œ๋น„์Šค ๊ฐ€์ž…์„ ๋งˆ์นœ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ ํ™œ์„ฑ Google ๊ณ„์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ์›น ์„œ๋น„์Šค์— ๋กœ๊ทธ์ธํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

 

 

 

 

 

 

Google Login Flow ( ์šฐ๋ฆฌ ์›น ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ)

 

1. Google API Console ์˜ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด ํƒญ์—์„œ  OAuth 2.0 client ์ •๋ณด ์ƒ์„ฑ ๋˜๋Š” ํ™•์ธ. (clientId)

 

2. web-front ์ฝ”๋“œ์— gsi/client srcipt ์‚ฝ์ž….

 

3. 1๋ฒˆ์˜ clientId ๋ฐ ์‚ฌ์šฉ์ž ์ธ์ฆ์— ๋Œ€ํ•œ ์‘๋‹ต callback์„ google initialize์•ˆ์— ์„ธํŒ….

 

4. ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋ฐœ์ƒ์‹œํ‚ฌ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ , Google์—์„œ ์‘๋‹ต๋ฐ›์€ accessToken(credential)์„ ์ด์šฉํ•˜์—ฌ, ์„œ๋ฒ„์—์„œ google์ธก์— ํ† ํฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ›„ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์š”์ฒญํ•˜์—ฌ ์‘๋‹ต์„ ๋ฐ›์Œ.

 

5. ์‘๋‹ต ๋ฐ›์€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํ†ตํ•ด ์›น ์„œ๋น„์Šค์˜ ํšŒ์›๊ฐ€์ž…์„ ์ง„ํ–‰ (์ด ๊ณผ์ •์—์„œ ์›น front๋‹จ์—์„œ ์„œ๋น„์Šค ์ด์šฉ ์•ฝ๊ด€ ๋™์˜ ๋“ฑ์„ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐ›๋Š”๋‹ค.)

 

6. ์›น ์„œ๋น„์Šค์— ํšŒ์›๊ฐ€์ž… ๋ฐ ๋กœ๊ทธ์ธ ์™„๋ฃŒ.

 

 


 

 

Google๋กœ ๋กœ๊ทธ์ธํ•˜๊ธฐ ๋ฒ„ํŠผ ๋…ธ์ถœ ๋ฐฉ๋ฒ•(๊ตฌ๊ธ€์—์„œ ์ง€์›ํ•˜๋Š” ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋…ธ์ถœ ๋ฐฉ๋ฒ•) 

 

 

 

 

1.  ์ฝ”๋“œ์— gsi/client srcipt ์‚ฝ์ž… 

<script src="https://accounts.google.com/gsi/client" async defer></script>

 

 

 

 

 

2. clientId ๋ฐ ์‚ฌ์šฉ์ž ์ธ์ฆ์— ๋Œ€ํ•œ ์‘๋‹ต callback์„ google initialize์•ˆ์— ์„ธํŒ… ๋ฐ renderButton method๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌ๊ธ€ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ Œ๋”๋ง ์‹œ์ผœ์คŒ.

 

window.onload = function () {
          google.accounts.id.initialize({
            client_id: "YOUR_GOOGLE_CLIENT_ID",
            callback: handleCredentialResponse
          });
          google.accounts.id.renderButton(
            document.getElementById("buttonDiv"),
            { theme: "outline", size: "large" }  // customization attributes
          );
          google.accounts.id.prompt(); // also display the One Tap dialog
        }

++ renderButtom ์†์„ฑ ๊ฐ’ ์ฐธ๊ณ 

 

 

 

 

 

3. ์ „์ฒด ์ฝ”๋“œ

<html>
  <body>
      <script src="https://accounts.google.com/gsi/client" async defer></script>
      <script>
         function handleCredentialResponse(response) {
          // response์— accessToken์ธ credential๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. 
              console.log("Encoded JWT ID token: " + response.credential);
            }
            window.onload = function () {
              google.accounts.id.initialize({
                client_id: "YOUR_GOOGLE_CLIENT_ID",
                callback: handleCredentialResponse
              });
              google.accounts.id.renderButton(
                document.getElementById("buttonDiv"),
                { theme: "outline", size: "large" }  // customization attributes
              );
              google.accounts.id.prompt(); // also display the One Tap dialog
        }
    </script>
    <div id="buttonDiv"></div> 
  </body>
</html>

 

 

 

 

 

 

 

++ ์ฐธ๊ณ  - initialize ์†์„ฑ ๊ฐ’. 

 

google.account.id.initialize({ client_id, callback })

 

google.accounts.id.initialize ์„ค์ • ๊ฐ’

 

 

Google JavaScript API๋กœ ๋กœ๊ทธ์ธ ์ฐธ์กฐ  |  Authentication  |  Google Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Switch to English ์˜๊ฒฌ ๋ณด๋‚ด๊ธฐ Google JavaScript API๋กœ ๋กœ๊ทธ์ธ ์ฐธ์กฐ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ

developers.google.com

 

 

 

 

 


 

 

Next.js๋ฅผ ์ด์šฉํ•œ Google Login ๊ตฌํ˜„ ์ฝ”๋“œ ( ์ฝ”๋“œ ์˜ˆ์‹œ )

 

import React, { useRef } from 'react';
import { GOOGLE_CLIENT_ID } from '../../../../common/const';
import useSocialLogin from '../../../../utils/useSocialLogin';

interface GoogleLoginProviderProps {
  children?: any;
}

const GoogleLoginProvider = ({ children }: GoogleLoginProviderProps) => {

  const googleRef = useRef<HTMLDivElement>();
  // ํ•ด๋‹น ๋ถ€๋ถ„์€ ๊ฐ ์†Œ์…œ ๋กœ๊ทธ์ธ๋ณ„ response accessToken๋ฅผ ๋ฐ›์•„์„œ ์šฐ๋ฆฌ ์„œ๋ฒ„์— ๋ณด๋‚ด์ฃผ๋Š” ์ปค์Šคํ…€ hook.
  const { responseCallback } = useSocialLogin({ socialId: 'google' });


  useEffect(() => {
    const script = document.createElement('script');
    script.src = 'https://accounts.google.com/gsi/client';
    document.body.appendChild(script);
    
    script.onload = () => {
      const { google } = window as any;
      const redirectUrl = `${location.origin}/login`;

      google.accounts.id.initialize({
        client_id: GOOGLE_CLIENT_ID,
        callback: onSignIn,
        auto_select: false,
        login_uri: redirectUrl,
      });
      google.accounts.id.renderButton( googleRef.current, {
     theme: "outline", size: "large" });
    };
  }, []);

  const onSignIn = async (res) => {
    await responseCallback({accessToken: res.credential});
  };

  return (
    <div style={{position: 'relative'}}>
	<!-- ๋‚˜๋Š” ์ปค์Šคํ…€ ๋””์ž์ธ ๋ฒ„ํŠผ ์‚ฌ์šฉ์„ ์œ„ํ•ด, ์‹ค์ œ google-login-button์„ css๋กœ ๋ณด์ด์ง€ ์•Š๊ฒŒ ์ฒ˜๋ฆฌํ•ด์ฃผ์—ˆ๋‹ค. -->
        <div 
          id="google-login-button"
          ref={googleRef}
          style={{ opacity: 0, position: 'absolute', zIndex: 100, left: 0, top: 0, right:0, bottom: 0 }}
          />
          <div>
            {children}
          </div>
    </div>
  );
};

export default GoogleLoginProvider;

 

 

 

 

 

 

++ ์ฐธ๊ณ  - responseCallback์—์„œ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์˜ accessToken ๊ฐ’๊ณผ socialId ๊ฐ’์„ ๋ฐ›์•„์„œ, ์šฐ๋ฆฌ ์„œ๋น„์Šค์˜ ๋กœ๊ทธ์ธ ๋กœ์ง์„ ํƒœ์›Œ ๋กœ๊ทธ์ธ์„ ์‹œ๋„ํ•˜๊ณ , ์‚ฌ์šฉ์ž ๊ณ„์ • ์ •๋ณด๊ฐ€ ์—†์„ ์‹œ(์„œ๋น„์Šค์— ํšŒ์› ๊ฐ€์ž…ํ•œ ์œ ์ €๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ) ํŽ˜์ด์ง€ redirect๋ฅผ ํ†ตํ•ด ํšŒ์› ๊ฐ€์ž…์„ ๋กœ์ง์„ ํƒ€๊ฒŒ ๋œ๋‹ค.

 

 

 

 

 


 

๐ŸŒธ ์ถœ์ฒ˜ ๐ŸŒธ

 

OAuth 2.0์„ ์‚ฌ์šฉํ•˜์—ฌ Google API์— ์•ก์„ธ์Šค ํ•˜๊ธฐ

์›น์šฉ Google ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ