본문 바로가기
개발

카카오 로그인

by ^..^v 2023. 4. 6.
728x90
반응형

MySQL, React, SpringBoot로 구현한 게시판 서비스에 카카오 로그인 기능을 추가하는 과정으로, 실습에 사용한 코드는 https://myanjini.tistory.com/entry/board-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C 에서 내려받을 수 있습니다. 

 

애플리케이션 추가

카카오 개발자 사이트(https://developers.kakao.com/)에서 애플리케이션을 추가하고, 앱 키를 확인합니다. (여기에서는 JavaScript SDK를 사용하므로,  JavaScript 키를 필요로 합니다.)

 

플랫폼 메뉴에서 사이트 도메인을 등록하고, Redirect URI 등록 페이지에서 카카오 로그인 서비스를 활성화하고, Redirect URI 주소를 등록합니다.

 

 

동의항목 메뉴에서 로그인 후 제공할 정보를 체크합니다.

 

라이브러리 등록

SDK 다운로드 페이지(https://developers.kakao.com/docs/latest/ko/sdk-download/js)에서 최신 버전의 코드를 포함하는 <script> 태그를 확인합니다. 

 

index.html 파일에 앞에서 복사항 <script> 태그를 추가합니다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    		... (생략) ...
    <!-- Kakao SDK for JavaScript 추가 -->
    <script src="https://t1.kakaocdn.net/kakao_js_sdk/2.1.0/kakao.min.js" integrity="sha384-dpu02ieKC6NUeKFoGMOKz6102CLEWi9+5RQjWSV0ikYSFFd8M3Wp2reIcquJOemx" crossorigin="anonymous"></script>
  </head>
  <body>
			... (생략) ...
  </body>
</html>

 

카카오 로그인 컴포넌트 추가

KakaoLogin.js 파일을 생성하고, 아래 코드를 추가합니다. 해당 코드는 샘플 페이지(https://developers.kakao.com/docs/latest/ko/kakaologin/js)의 소스코드를 참고해서 작성했습니다.

import axios from 'axios';
import { useState } from 'react';
import { useEffect } from "react";

const KakaoLogin = () => {
    const { Kakao } = window;

    const JAVASCRIPT_APP_KEY = 'be837b733c72053ebc27ab95eea89861';
    
    // 액세스 토큰을 상태 변수로 선언 
    // 로그인 버튼 출력 제어에 사용
    const [accessToken, setAccessToken] = useState('');

    const handlerLogin = () => {
        // 간편 로그인을 요청
        // 인증 성공 시 redirectUri 주소로 인가 코드를 전달
        Kakao.Auth.authorize({
            redirectUri: 'http://localhost:3000/kakaoLogin'
        });
    };

    useEffect(() => {
        Kakao.init(JAVASCRIPT_APP_KEY);

        // 쿼리 스트링으로 부터 인가 코드를 추출
        const code = window.location.search.split('=')[1];
        if (code) {
            // REST API로 토큰 받기를 요청
            axios.post(
                'https://kauth.kakao.com/oauth/token', {
                    grant_type: 'authorization_code',                   // 고정
                    client_id: JAVASCRIPT_APP_KEY,                      // 앱 REST API 키
                    redirect_uri: 'http://localhost:3000/kakaoLogin',   // 인가 코드가 리다이렉트된 URI
                    code: code                                          // 인가 코드 받기 요청으로 얻은 인가 코드
                }, {
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
                    }
                }
            )
            .then(response => {
                const accessToken = response.data.access_token;         // 사용자 액세스 토큰 값
                setAccessToken(accessToken);
                
                // 액세스 토큰 값을 할당
                Kakao.Auth.setAccessToken(accessToken);

                // 사용자 정보 가져오기
                Kakao.API.request({
                    url: '/v2/user/me'
                })
                .then(response => {
                    // 사용자 정보 로깅
                    console.log(response);

                    // 애플리케이션에서 필요한 정보를 추출해서 로컬 스토리지에 저장
                    const { kakao_account } = response;
                    localStorage.setItem('userName', kakao_account.profile.nickname);
                    localStorage.setItem('userNickname', kakao_account.profile.nickname);
                    localStorage.setItem('userPhoto', kakao_account.profile.profile_image_url);

                    // 홈(/) 화면으로 이동
                    window.location.href = "/";
                })
                .catch(error => {
                    console.log(error);
                });
            })
            .catch(error => console.log(error));          
        }
    }, []);

    

    return (
        <>
            {/* https://developers.kakao.com/tool/resource/login */}
            { !accessToken && 
                <img style={{width: 277, height: 60, cursor: 'pointer'}} 
                     src="https://developers.kakao.com/tool/resource/static/img/button/login/full/ko/kakao_login_medium_wide.png" 
                     onClick={handlerLogin} /> 
            }
        </>
    );
};

export default KakaoLogin;

 

Login.js 수정

로그인 컴포넌트에 카카오 로그인 컴포넌트를 추가합니다.

import KakaoLogin from "./KakaoLogin";
import NaverLogin from "./NaverLogin";
import { useEffect } from "react";

const Login = () => {

    useEffect(() => {
        // 로컬 스토리지에 userName이 존재하는 경우 로그인한 것으로 판단
        // 이미 로그인한 경우 홈(/)으로 이동
        const isLogin = !!window.localStorage.getItem('userName');
        if (isLogin) {
            window.location.href = '/';
        }
    }, []);

    return (
        <>
            <div style={{ textAlign: 'center', padding: '30px' }}>
                <NaverLogin />
                <KakaoLogin />	{/* 카카로 로그인 컴포넌트 추가 */}
            </div>
        </>
    );
};

export default Login;

 

App.js 수정

간편 인증 결과 및 토큰 요청 결과를 전달받을 콜백 URL을 라우터로 등록합니다.

import './App.css';
import { Route } from 'react-router-dom';
import BoardList from "./board/BoardList";
import BoardDetail from "./board/BoardDetail";
import BoardWrite from './board/BoardWrite';
import Login from './Login';
import KakaoLogin from './KakaoLogin';

const App = () => {
  // 로그인 페이지로 이동
  const handlerLogin = (e) => {
    e.preventDefault();
    window.location.href = '/login';
  };

  // 로그아웃 처리 
  // 로컬 스토리지 내용 삭제 후 홈(/)으로 이동
  const handlerLogout = (e) => {
    e.preventDefault();
    localStorage.clear();
    window.location.href = '/';
  };

  // 로그인 페이지가 아닌 경우 로그인/로그아웃 버튼을 제공
  // 로그인 상태인 경우 로그인 정보와 로그아웃 버튼을 
  // 로그아웃 상태인 경우 로그인 버튼을 제공
  const isNotLoginPage = window.location.pathname === '/login' ? false : true;
  const isLogin = !!window.localStorage.getItem('userName');
  
  return (
    <>
      <div style={{ textAlign: 'right', padding: '30px' }}>
        { isNotLoginPage && isLogin && 
          <> 
            { window.localStorage.getItem('userName') }님 환영합니다.
            &nbsp;
            <button onClick={handlerLogout}>Logout</button>
          </> 
        }
        { isNotLoginPage && !isLogin && 
          <>
            <button onClick={handlerLogin}>Login</button>
          </>
        }        
      </div>

      <Route path="/" component={BoardList} exact={true} />
      <Route path="/login" component={Login} exact={true} />
      <Route path="/kakaoLogin" component={KakaoLogin} exact={true} />  {/* 라우터 추가 */ }
      <Route path="/board" component={BoardList} exact={true} />
      <Route path="/board/write" component={BoardWrite} />
      <Route path="/board/detail/:boardIdx" component={BoardDetail} />
    </>
  );
};

export default App;

 

실행 결과

 

최종 코드

board-react_kakao.zip
1.11MB

728x90
반응형

댓글