카카오, 구글 로그인 구현하기(vite+react)

혜진 조·2024년 8월 8일
0

리액트

목록 보기
31/31

카카오 로그인 구현 (REST API 방식)

useKakaoLogin hook을 생성

//useKakaoLogin.ts
import axios from "axios";
import axiosInstance from "../api/axiosInstance";
import { useLogin } from "./useLogin";

export const useKakaoLogin = () => {
  const { mutate } = useLogin();
  const state = "kakao"; //OAuth서버로 부터 전달 받을 state 값을 설정
  const CLIENT_ID = import.meta.env.VITE_KAKAO_REST_API_KEY; //vite 사용 시 .env 파일의 환경변수는 import.meta.env.변수명 형태로 가져옵니다.
  const REDIRECT_URI = import.meta.env.VITE_KAKAO_REDIRECT_URL;
  const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&state=${state}`;

  const queryParams = new URLSearchParams(window.location.search);
  const code = queryParams.get("code"); //Redirect URI 쿼리 파라미터의 code 값을 가져옵니다.

  const kakaoLogin = async () => {
    const response = await axios({
      method: "post",
      url: "https://kauth.kakao.com/oauth/token",
      data: {
        grant_type: "authorization_code",
        client_id: CLIENT_ID,
        redirect_uri: REDIRECT_URI,
        code,
      },
      headers: {
        "Content-type": " application/x-www-form-urlencoded;charset=utf-8",
      },
    });
        
    if (response.data.access_token) {
      //verify account
      (async () => {
        const res = await axiosInstance.post(
          "verify account api",
          {
            token: response.data.access_token,
          }
        );
        const { result, email } = res.data.data;

        if (result) {
          if (result === "VERIFIED") {
            /* VERIFIED: 검증 성공하였으나 등록되지 않은 회원 */
            // 회원가입 페이지로 이동
          } else if (result === "SUCCESS") {
            /* SUCCESS:이미 가입된 회원 */
            //login
            mutate({
              email,
              snsPlatform: "kakao",
            });
          } else {
            /* INVALID: 토큰 유효하지 않음 */
            console.log("Error: 토큰정보가 유효하지 않습니다.");
          }
        }
      })();
    }
  };
  return { kakaoLogin, KAKAO_AUTH_URL };
};

KakaoLoginButton 컴포넌트

//kakaoLoginButton.tsx
import { useEffect } from "react";
import KakaoLogo from "../../assets/icons/kakaoLogo.svg";
import { useKakaoLogin } from "../../lib/hooks/useKakaoLogin";

function KakaoLoginButton() {
  //useKakaoLogin hook 사용
  const { kakaoLogin, KAKAO_AUTH_URL } = useKakaoLogin();

  useEffect(() => {
    const queryParams = new URLSearchParams(window.location.search);
    const code = queryParams.get("code");
    const state = queryParams.get("state");
    
    //구글, 카카오 로그인 모두 REDIRECT_URI/?code=123123123 로 리다이렉트처리되므로 state 값 설정을 통해 플랫폼의 종류를 구분할 수 있습니다.
    //state 설정 시 ==> REDIRECT_URI/?code=123123123&state=kakao
    if (code && state === "kakao") {
      kakaoLogin();
    }
  }, []);

  return (
    <button
      onClick={() => (window.location.href = KAKAO_AUTH_URL)}
    >
      <img src={KakaoLogo} alt="Kakao 로그인 로고" />
      카카오톡으로 로그인하기
    </button>
  );
}

export default KakaoLoginButton;

구글로그인도 동일한 방식입니다.

useGoogleLogin hook 생성

//useGoogleLogin.ts

import axios from "axios";
import { useLogin } from "./useLogin";
import axiosInstance from "../api/axiosInstance";

export const useGoogleLogin = () => {
  const { mutate } = useLogin();
  const state = "google";
  const CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID;
  const CLIENT_SECRET = import.meta.env.VITE_GOOGLE_CLIENT_SECRET;
  const REDIRECT_URI = import.meta.env.VITE_GOOGLE_REDIRECT_URL;
  const GOOGLE_AUTH_URL = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=profile%20email&state=${state}`;

  const queryParams = new URLSearchParams(window.location.search);
  const code = queryParams.get("code");

  const googleLogin = async () => {
    const response = await axios("https://oauth2.googleapis.com/token", {
      method: "post",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      data: {
        code,
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET,
        redirect_uri: REDIRECT_URI,
        grant_type: "authorization_code",
      },
    });
    if (response.data.access_token) {
      //verify account
      (async () => {
        const res = await axiosInstance.post(
          "veriry accout api",
          {
            token: response.data.id_token,
          }
        );
        const { result, email } = res.data.data;

        if (result) {
          if (result === "VERIFIED") {
            /* VERIFIED: 검증 성공하였으나 등록되지 않은 회원 */
            //회원가입 페이지 이동
          } else if (result === "SUCCESS") {
            /* SUCCESS:이미 가입된 회원 */
            //login
            mutate({
              email,
              snsPlatform: "google",
            });
          } else {
            /* INVALID: 토큰 유효하지 않음 */
            console.log("Error: 토큰정보가 유효하지 않습니다.");
          }
        }
      })();
    }
  };

  return { googleLogin, GOOGLE_AUTH_URL };
};

GoogleLoginButton 컴포넌트

//GoogleLoginButton.tsx

import { useEffect } from "react";
import GoogleLogo from "../../assets/icons/googleLogo.svg";
import { useGoogleLogin } from "../../lib/hooks/useGoogleLogin";

function GoogleLoginButton() {
  const { googleLogin, GOOGLE_AUTH_URL } = useGoogleLogin();

  useEffect(() => {
    const queryParams = new URLSearchParams(window.location.search);
    const code = queryParams.get("code");
    const state = queryParams.get("state"); // OAuth2 서버가 전달한 state 파라미터
    if (code && state === "google") {
      googleLogin();
    }
  }, []);
  return (
    <button
      onClick={() => (window.location.href = GOOGLE_AUTH_URL)}
    >
      <img src={GoogleLogo} alt="Google 로고" />
      구글로 로그인하기
    </button>
  );
}

export default GoogleLoginButton;
profile
나를 믿고 한 걸음 한 걸음 내딛기! 🍏

0개의 댓글