카카오 로그인 기능 구현 - 프론트(리액트)

DangDu Lee·2020년 12월 25일
0
post-custom-banner

전체적인 흐름:


(redirect_uri, 사이트 도메인 등록 방법을 다른 블로그에 많기 때문에 이 글에 따로 적지는 않겠다.)

카카오 로그인은 프론트, 서버 중 한쪽 사이드에서 모든 과정을 처리할 수 있다.
하지만 서버에서 모두 처리할 경우, 프론트에서 로그인을 요청했을 때 로그인 정보와 함께 리다이렉팅을 어떻게 할지 아이디어가 잘 떠오르지 않았다.
그리고 프론트에서 모두 처리할 경우, Kakao.Auth.login() 안에 Kakao.API.request() 함수 안에 axios 함수까지 써야 하기 때문에 콜백 지옥에 빠질 것 같아 서버에서 직접 사용자 정보를 가져오려 했다.
(Kakao.Auth.authorize()를 시도해봤지만 잘 안됐고, Kakao.Auth.login()에 파라미터로 success, fail을 넣어야 해서 async/await로 구현하는 건 더 복잡해질 수 있다고 판단했다)

1. 프론트 구성

  1. 필요한 모듈들 설치(useState도 가능하지만, recoil을 선호해서, 상태 관리는 recoil로 했다.
  npm i --save kakaojs axios js-cookie react-router-dom recoil
  1. 카카오 sdk 설정
  <!--index.html에 아래 태그 추가-->
  <script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
//index.js
... 
import {RecoilRoot} from 'recoil';


ReactDOM.render(
  <React.StrictMode>
    <RecoilRoot> //recoil State
      <App />
    </RecoilRoot>
  </React.StrictMode>,
  document.getElementById('root')
);


// App.js
import Kakao from 'kakaojs';
import React from 'react';
import AppRouter from './Router';

function App(){
  React.useEffect(( ) => {
      window.Kakao.init('JavaScript 키'); // 배포할 땐 .env 파일에 넣어서 쓸 예정이다.
      Kakao.isInitialized();
  }, []);
  return (
    <div className="App">
      <AppRouter />
    </div>
  );
};
  1. access_token 발급받고 서버에 전달한 뒤, 로그인 처리
//Router.js
import React from 'react';
import {BrowserRouter,  Route, Switch } from "react-router-dom";
import SignUp from './SignUp';
import Home from './Home';

const AppRouter = () => {
    return (
        <BrowserRouter>
        <Switch> 
            <Route exact path="/"> 
                <Home />
            </Route>
            <Route path="/sign-up">
                <SignUp />
            </Route>
        </Switch>
        </BrowserRouter>
    )
};


// Home.js
import axios from 'axios';
import Kakao from 'kakaojs';
import React from 'react';
import Cookies from 'js-cookie';
import ProfileState from './ProfileState';
import {useSetRecoilState} from 'recoil';
import { useHistory } from "react-router-dom";

const Home = () => {
  const history = useHistory();
  const setProfile = useSetRecoilState(ProfileState);
  const signIn = () => {
    axios.defaults.xsrfCookieName = "csrftoken"
    axios.defaults.xsrfHeaderName = "X-CSRFToken" // 서버에 CSFR 토큰을 넘겨야 함.
    Kakao.Auth.login({
      scope: 'profile',
      success: (res) => {
        console.log('first res:', res)
        Kakao.Auth.setAccessToken(res.access_token);

        const csrftoken = Cookies.get('csrftoken');
        axios.post('http://127.0.0.1:8000/account/login/kakao/', {
          headers:{
             "Access-Control-Allow-Origin": '*',
             'Accept': 'application/json',
             'Content-Type': 'application/json',
             'X-CSRFToken': csrftoken
          },
          data: {
            access_token: res.access_token
          }
        })
        .then((res) => {
          if (res.status === 203) { // 가입되지 않은 사용자일 경우 회원가입 부분으로 넘김
            setProfile(res.data);
            history.push("/sign-up");
          } else if (res.status === 200) { // 가입된 사용자일 경우 로그인 성공 처리
            window.alert("login completed");
          }
        })
        .catch((err) => console.log(err))
      }, 
      fail: (err) => {
          console.error(err);
      }
    });
  };


  return (
    <div className="home">
      <button onClick={signIn}>로그인</button>
    </div>
  );
};

// ProfileState.js
import {atom} from 'recoil';

const ProfileState = atom({
    key: 'profileState',
    default: {}
});


// SignUp.js
import React from "react";
import { useHistory } from "react-router-dom";
import axios from 'axios';
import Cookies from 'js-cookie';
import ProfileState from './ProfileState';
import {useRecoilValue} from 'recoil';

const SignUp = () => {
    const history = useHistory();
    const profile = useRecoilValue(ProfileState);
    const [gSchoolNickname, setNickname] = React.useState('');

    const signUp = () => {
        const kakao_profile_info = profile.kakao_profile;
        const csrftoken = Cookies.get('csrftoken');
        axios.post('http://127.0.0.1:8000/account/sign-up/kakao/', {
          headers:{
              "Access-Control-Allow-Origin": '*',
              'Accept': 'application/json',
              'Content-Type': 'application/json',
              'X-CSRFToken': csrftoken
          },
          data: {
            kakao_id: profile.kakao_id,
            g_school_nickname: gSchoolNickname, // 학교에서 사용하는 별명
            kakao_nickname: kakao_profile_info.nickname,
            profile_image: kakao_profile_info.thumbnail_image_url,
            access_token: profile.access_token
          }
        })
        .then((res) => {
            history.push('/')
        })
        .catch((err) => console.log(err))
    };


    return (
        <div>
            <input type="text" value={gSchoolNickname} onChange={(e) => setNickname(e.target.value)} maxLength={2} />
            <button onClick={signUp}>회원 가입</button>
        </div>
    )
};

아직 개발이 진행 중이기 때문에, 세부 설명들은 나중에 올릴게요..

post-custom-banner

0개의 댓글