[Week2] Google Login

👻 Google Login

1. 구글 API 등록

구글 API 등록 링크 접속 후, 프로젝트 생성
그 후에 API 및 서비스로 이동 후, OAuth 동의 화면 선택!
프로젝트 이름 옆에 위치한, 앱 수정 버튼 클릭

범위 추가 또는 삭제 버튼을 클릭해서 필요한 정보를 불러오기 위해 범위 설정(!!중요한 부분!!)

페이지 하단의 저장 후 계속 버튼 클릭 후, 마지막 페이지에서 대시보드로 돌아가기 버튼 클릭하면 OAuth 동의 화면 설정 완료 🙂

그러면 이제 사용자 인증 정보 설정하러 고고!

사용자 인증 정보 만들기 버튼 클릭후, OAuth 클라이언트 ID 클릭

애플리케이션 유형은 웹 애플리케이션 선택! (프로젝트 유형에 맞게 선택하면 될 듯)

승인된 리디렉션 URI는 우리 프로젝트의 api에 맞게끔 주소 설정
나중에 배포하게 되면, 이 곳에 배포링크 추가해줘야 배포 후에도 구글 소셜 로그인 사용이 가능

만들기 버튼을 클릭하면, 클라이언트 ID와 클라이언트 보안 비밀번호가 발급되는데 잘 보관해두고, 유출되지 않게 조심!!

그리고 클라이언트 ID는 .env 파일이나 별도의 파일에 잘 복붙해놓기

2. client 설정

홈페이지에서 구글 로그인 버튼을 누르면, 아래 코드가 실행됨

React에서 .env 환경 변수 설정시,
환경 변수 앞에 꼭 REACT_APP 붙여줘야함!!!

const handleGoogle = () => {
	const GOOGLE_LOGIN_URL = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${process.env.REACT_APP_GOOGLE_CLIENT_ID}&redirect_uri=${process.env.REACT_APP_GOOGLE_REDIRECT_URI}&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile`;
    window.location.assign(GOOGLE_LOGIN_URL);
  };

우리 프로젝트에서는 구글 로그인시, 구글 이메일 정보와 구글 닉네임 정보가 필요했기에
아래 주소에서 scope 설정시 2개의 정보를 요청해야 했음

scope 부분만 별도로 기록을 해보자면,
1개 이상의 scope이 필요할시에는 api 주소 사이에 띄어쓰기를 해주면 잘 작동함
(이거 완전 꿀팁!)

scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile`;

그리고 사용할 수 있는 scope 설정은 위의 API 설정에서
범위 추가 또는 삭제를 통해 범위를 추가해줘야 추가해준 범위에 한해서 scope 설정이 가능 😎

Router.js 파일에 아래와 같이 라우트 추가

<Route path="/google/signin" element={<Google />} />

Google.js 파일 설정은 아래와 같이 😎

import { useState, useEffect } from 'react';
import axios from 'axios';
import { useDispatch } from 'react-redux';
import { socialSignIn, setSocialUser } from '../../redux/user/userSlice';
import { useNavigate } from 'react-router-dom';

const Google = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const [token, setToken] = useState();

  const getGoogleCode = () => {
    const googleCode = new URL(window.location.href).searchParams.get('code');
    if (googleCode) {
      getToken(googleCode);
    }
  };

  const getToken = async (code) => {
    try {
      const data = await axios.post('/google/signin', {
        code,
      });
      setToken(data.data.access_token);
    } catch (e) {
      console.log(e);
    }
  };

  const getUserInfo = async (token) => {
    try {
      const data = await axios.get(`/google/user?accessToken=${token}`);
      if (data) {
        const { email, name, user_type: who } = data.data.giverInfo;
        dispatch(socialSignIn());
        dispatch(setSocialUser({ email, name, who }));
        localStorage.setItem('token', token);
        navigate('/');
      }
    } catch (e) {
      console.log(e);
    }
  };

  useEffect(() => getGoogleCode(), []);

  useEffect(() => getUserInfo(token), [token]);

  return (
    <>
      <div></div>
    </>
  );
};

export default Google;

3. server 설정

router 파일에 아래 내용 추가

router.post('/google/signin', user.googleLogin.getToken);
router.get('/google/user?', user.googleLogin.getUser);

googleLogin.js 파일 설정은 아래와 같이 😎

'use strict';
const axios = require('axios');
const jwt = require('jsonwebtoken');
const { giver } = require('../../models');

module.exports = {
  getToken: async (req, res) => {
    const code = req.body.code;
    const url = `https://oauth2.googleapis.com/token?code=${code}&client_id=${process.env.GOOGLE_CLIENT_ID}&client_secret=${process.env.GOOGLE_CLIENT_SECRET}&redirect_uri=${process.env.GOOGLE_REDIRECT_URI}&grant_type=${process.env.GOOGLE_GRANT_TYPE}`;
    try {
      const token = await axios.post(url, {
        headers: { 'content-type': 'application/x-www-form-urlencoded' },
      });
      const data = token.data;
      res.send(data);
    } catch (e) {
      console.log(e);
    }
  },
  getUser: async (req, res) => {
    const token = req.query.accessToken;
    const googleAPI = `https://www.googleapis.com/oauth2/v2/userinfo?access_token=${token}`;
    try {
      const googleUser = await axios.get(googleAPI, {
        headers: {
          authorization: `Bearer ${token}`,
        },
      });
      const user = googleUser.data;

      const giverFound = await giver.findOne({ where: { email: user.email } });

      if (giverFound) {
        const giverInfo = giverFound.dataValues;
        delete giverInfo.password;
        const accessToken = jwt.sign(giverInfo, process.env.ACCESS_SECRET);
        res.send({ accessToken, giverInfo });
      } else {
        const newGiver = await giver.create({
          email: user.email,
          name: user.name === '' ? '' : user.name,
          user_type: 1,
        });
        const { id, email, name, user_type } = newGiver.dataValues;
        const giverInfo = { id, email, name, user_type };
        const accessToken = jwt.sign(giverInfo, process.env.ACCESS_SECRET);
        res.send({ accessToken, giverInfo });
      }
    } catch (e) {
      console.log(e);
    }
  },
};

좋은 웹페이지 즐겨찾기