프로젝트/하루한냥

[하루한냥] 로그인/회원가입 : 카카오 소셜 로그인 구현

알파카털파카 2023. 7. 18. 00:32
[하루한냥]
로그인/회원가입 : 카카오 소셜 로그인 구현

 

 

서비스를 이용하려면 로그인 기능이 필요하다. 하루한냥 서비스의 자체 로그인/회원가입 기능을 완성했다. 이후의 태스크는 카카오 소셜 로그인을 구현하는 것이다. 백엔드 처리가 필요해서 이 부분은 멘토님이 맡아주셨다. 나는 카카오 디벨로퍼스 공식 문서와 백엔드에서 만든 API를 참고해 REST API 형식으로 카카오 소셜 로그인을 구현했다. 

 

 


 

 

1. 애플리케이션 추가

Kakao Developers 에 회원가입/로그인하고 내 애플리케이션에 들어가 새로운 애플리케이션을 추가한다. 앱을 추가하면 앱 키가 발급된다. 왼쪽의 설정 메뉴에서 카카오 로그인을 클릭하면 카카오 로그인을 활성화할 수 있다. 

 

하루한냥 애플리케이션 추가

 

앱 키 발급

 

카카오 로그인 활성화

 

하루한냥 프로젝트에서는 이메일 ID와 비밀번호, 닉네임을 사용하기 때문에 카카오 로그인으로 서비스를 시작할 때 '닉네임'만 필수로 받아오도록 설정했다.

 

동의 항목

 

 

 

2. 카카오 로그인 버튼 기능 구현

UI만 완성해 두었던 홈 화면에서 카카오 로그인 버튼에 기능을 추가해 보자. 카카오 디벨로퍼스의 REST API로 카카오 로그인 구현하기 공식 문서를 참고했다. 내용이 자세하게 설명되어 있기 때문에 차근차근 읽어보면 좋다.

 

홈 화면

 

// 카카오 예제 코드

https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code

 

카카오 예제 코드를 살펴보면 REST_API_KEY와 REDIRECT_URI의 값을 변수로 넣어주고 있다. 이 값은 아까 발급받은 앱 키와 리다이렉트 URI를 넣어주면 된다. 하드 코딩을 방지하기 위해 config 파일에 변수를 모아두었다.

 

// src/lib/const/config.ts

const KAKAO_CLIENT_ID = '애플리케이션의 REST API KEY';
const KAKAO_REDIRECT_URL = 'http://localhost:5173/oauth/kakao';
export const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_CLIENT_ID}&redirect_uri=${KAKAO_REDIRECT_URL}&response_type=code`;
// src/pages/HomePage.tsx

  const handlePageAuthKakao = () => {
    location.href = KAKAO_AUTH_URL;
  };

 

위의 함수를 카카오 로그인 버튼에 onClick으로 연결해주면 된다.

 

 

 

3. 리다이렉션 페이지 생성 

카카오 로그인 버튼을 클릭하면 카카오로 서비스를 시작하기 위해 처음 뜨는 사용자 동의 화면이 뜬다. 동의하고 계속하기를 누르면 정상적으로 회원가입되고 서비스를 이용할 수 있다. 이 때 리다이렉션이 발생하는데, 로그인 설정에서 지정해 둔 Redirect URI로 리다이렉트가 이루어진다. 그렇기 때문에 비어있는 해당 페이지 컴포넌트를 하나 만들어준다.

 

사용자 동의 화면

 

// src/routes.tsx

const routes = [
  {
    element: <RouterLayout />,
    children: [
      { path: PATH.HOME, element: <HomePage /> },
      { path: PATH.SIGN_IN, element: <SigninPage /> },
      { path: PATH.SIGN_UP, element: <SignupPage /> },
      { path: PATH.CALENDAR, element: <CalendarPage /> },
      { path: PATH.TIMELINE, element: <TimelinePage /> },
      { path: PATH.REPORT, element: <ReportPage /> },
      { path: PATH.SETTING, element: <SettingPage /> },
      { path: PATH.OAUTH_KAKAO, element: <AuthKakaoPage /> }, // ✅ 추가
    ],
  },
];


// src/lib/const/path.ts

export const PATH = {
  ...
  OAUTH_KAKAO: '/oauth/kakao',
};

 

 

 

4. 엑세스 토큰 발급받기

리다이렉션이 일어나면 URL에 code 값이 담겨서 온다. 이 code 값만 추출해서 백엔드의 API로 body에 담아 보내면 엑세스 토큰을 얻을 수 있다. 이 부분은 useSearchParams를 사용했다.

 

import { useSearchParams } from 'react-router-dom';

export default function AuthKakaoPage() {
  const [params] = useSearchParams();
  const code = params.get('code');
  
  // ...
}

 

code를 보내고 받은 엑세스 토큰 값과 유저 이름을 로컬 스토리지에 저장하고, 로그인 후의 메인 기능 페이지인 캘린더 페이지로 이동시켜 주었다. 

 

const handleSigninKakao = async () => {
    const responseSignIn = await http.post('/user/oauth/kakao', { code });
    const isSuccess = responseSignIn.success;

    if (isSuccess) {
      const accessToken = responseSignIn.data.token;
      const userProfile = {
        name: responseSignIn.data.user.name,
      };
      localStorage.setItem(ACCESS_TOKEN, JSON.stringify(accessToken));
      localStorage.setItem(USER, JSON.stringify(userProfile));
      navigate(PATH.CALENDAR);
    }
  };

 

응답 타입 문제를 해결하고, response가 없을 경우를 대비하는 방어코드를 추가했다. try catch로 로그인에 실패했을 경우의 처리도 구현했다. useEffect와 useCallback을 사용해 메모이제이션 처리를 했다. 종합적인 코드는 다음과 같다.

 

import { useSearchParams } from 'react-router-dom';
import { useCallback, useEffect } from 'react';
import { useNavigate } from 'react-router';
import { PATH } from '@lib/const/path';
import { ACCESS_TOKEN, USER } from '@lib/const/localstorage';
import { handleAxiosError, http } from '../api/http';

export default function AuthKakaoPage() {
  const navigate = useNavigate();
  const [params] = useSearchParams();
  const code = params.get('code');

  const handleSigninKakao = useCallback(async () => {
    try {
      const responseSignIn = await http.post<{ token: string; user: { name: string } }>('/user/oauth/kakao', { code });
      const isSuccess = responseSignIn.success;
      if (isSuccess && responseSignIn.data) {
        const accessToken = responseSignIn.data.token;
        const userProfile = {
          name: responseSignIn.data.user.name,
        };
        localStorage.setItem(ACCESS_TOKEN, JSON.stringify(accessToken));
        localStorage.setItem(USER, JSON.stringify(userProfile));
        navigate(PATH.CALENDAR);
      }
    } catch (e) {
      const error = handleAxiosError(e);
      alert(error.msg);
      navigate(PATH.HOME);
    }
  }, [code, navigate]);

  useEffect(() => {
    if (code) {
      handleSigninKakao();
    }
  }, [code, handleSigninKakao]);

  return <div />;
}

 

 

 

5. 번외 - 자바스크립트 SDK 사용하기 

자바스크립트 SDK를 사용할 경우 JavaScript SDK 문서를 참고하면 된다. 나는 처음에 이 방법으로 구현했는데 이렇게 처리할 경우 KakaoTalk이라는 한 단계를 더 거쳐야 하기 때문에 좀 더 간편한 REST API 방식으로 교체하게 되었다. 교체하기 전까지의 코드를 조금 남겨본다. 

 

자바스크립트 SDK 로그인 과정

 

REST API 로그인 과정

 

index.html 파일의 <head>에 아래의 script를 추가해 SDK를 설치한다. Kakao.init()에 들어갈 자바스크립트 키는 내 애플리케이션의 앱 키에서 가져오면 된다. 

 

<script 
  src="https://t1.kakaocdn.net/kakao_js_sdk/2.3.0/kakao.min.js"
  integrity="INTEGRITY_VALUE 입력" 
  crossorigin="anonymous">
</script>
<script>
  Kakao.init(사용하려는 앱의 JavaScript 키 입력); 
</script>

 

카카오 로그인 버튼에 onClick 함수를 등록한다. 해당 함수는 다음과 같이 구현했다. 1번에서 설정해 두었던 redirectUri를 활용한다. 자바스크립트 SDK를 이용한 구현은 이정도까지 진행했었다. 

 

const handlePageAuthKakao = () => {
  Kakao.Auth.authorize({
    redirectUri: 'http://localhost:5173/oauth/kakao',
  });
};

 

 

 

 

마치며

소셜 로그인을 처음 구현해보는 점, 백엔드와 소통이 원활하지 못했던 점 등의 이유로 이틀 정도 소요되었다. 자바스크립트 SDK로 구현하다가 도중에 노선을 틀었지만 결과적으로는 두 가지 방법 모두 겪어보아서 오히려 더 배울 수 있었다.