본문 바로가기
개발

카카오 소셜 로그인

by sungin95 2023. 7. 5.

프로젝트에서 소셜 로그인 기능을 만들어 달라는 요청을 받았다. 

찾아보니 백엔드에서만 처리 할 수 있는 문제는 아니고 프론트와 같이 작업을 해야만 했다. 

그래서 문서를 만들어서 공유 할 겸 블로그로 적어본다. 

현재 스택은 React와 Django를 사용하고 있습니다. 

 

우선 키 발급 부터 포스트를 하겠습니다. 

 

우선 아래 사이트에서 애플리케이션을 추가해 주어야 합니다.

https://developers.kakao.com/docs/latest/ko/getting-started/app#platform

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

 

 

 

 

 

 

 

 

저장을 하시면 애플리케이션이 생성된 것을 확인 할 수 있습니다. 

해당 애플리케이션을 클릭해 줍니다. 

 

 

왼쪽에 메뉴에서  카카오 로그인을 클릭

 

활성화 선택 ON

Redirect URL 설정

참고: 나중에 배포하게 되시면 이 부분은 다시 와서 수정해야 합니다. 

 

그리고 동의 항목도 설정해 줍니다. 

 

동의 목적은 "서비스 이용"처럼 간단하게 작성해도 상관 없는거 같습니다. 

 

 

이제부터 말하는 키는 저 REST API키를 뜻합니다. 

 

그럼 이제 설명을 드리자면

아래 그림이 카카오 로그인 과정입니다.

우선 Step1에 대하여 홈페이지에서는 이렇게 설명되어 있습니다. 

1. 인가 코드 받기

1.서비스 서버가 카카오 인증 서버로 인가 코드 받기를 요청합니다.

2. 카카오 인증 서버가 사용자에게 카카오계정 로그인을 통한 인증을 요청합니다.

    클라이언트에 유효한 카카오계정 세션이 있거나, 카카오톡 인앱 브라우저에서의 요청인 경우 4단계로 넘어갑니다.

3. 사용자가 카카오계정으로 로그인합니다.

4. 카카오 인증 서버가 사용자에게 동의 화면을 출력하여 인가를 위한 사용자 동의를 요청합니다.

    동의 화면은 서비스 애플리케이션(이하 앱)의 동의 항목 설정에 따라 구성됩니다.

5. 사용자가 필수 동의 항목, 이 외 원하는 동의 항목에 동의한 뒤 [동의하고 계속하기] 버튼을 누릅니다.

6. 카카오 인증 서버는 서비스 서버의 Redirect URI로 인가 코드를 전달합니다.

 

Step1의 목표는 카카오 서버로 부터 정보를 받아서 백엔드로 보내는 일입니다.

그런데 1번부터 무슨 말이진 모르겠습니다. 

그래서 이것 저것 공부해 보니 1번이 뜻하는 것은

소셜 로그인 버튼 클릭입니다. 

버튼을 클릭했을 때, 카카오에서 정한 페이지형식에 맞추어서 보내면 아래의 페이지를 보여주겠다는 뜻입니다. 

페이지

그러면 카카오가 정한 페이지와 형식에 대한 정보는 무엇일까요?

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#kakaologin

형식

여기로 퀴리 파라미터 형식으로 보내면 됩니다. 목록은 아래 링크를 참고하세요.

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-code-request-query

 

저는 client_id, redirect_uri, response_type 3가지 필수 사항만 넣어서 작성해 보았습니다. 

예시

코드 완성 예시 입니다.

import { Box, Button, Divider, HStack, Text, VStack } from "@chakra-ui/react";
import { FaComment, FaGithub } from "react-icons/fa";

export default function SocialLogin() {
  const kakaoParams = {
    client_id: "REST API KEY",
    redirect_uri: "http://127.0.0.1:3000/social/kakao",
    response_type: "code",
  };
  const params = new URLSearchParams(kakaoParams).toString();
  return (
    <Box mb={4}>
      <VStack>
        <Button
          as={"a"}
          href={`https://kauth.kakao.com/oauth/authorize?${params}`}
          w="100%"
          leftIcon={<FaComment />}
          colorScheme={"yellow"}
        >
          Continue with Kakao
        </Button>
      </VStack>
    </Box>
  );
}

퀴리 파라미터 형식으로 적을 때 실수를 줄이기 위해 

  const kakaoParams = {
    client_id: "REST API KEY",
    redirect_uri: "http://127.0.0.1:3000/social/kakao",
    response_type: "code",
  };
  const params = new URLSearchParams(kakaoParams).toString();

이렇게 적고 변수화 하여 사용했습니다. 

 

이렇게 하면 6번까지 작업은 카카오에서 다 해 줍니다. 그러면 이제 리다일렉트 페이지에서 정보를 받아서 백엔드로 보낼 준비만 하면 됩니다. 

redirect_uri: "http://127.0.0.1:3000/social/kakao",

 

그러면 여기서 정보를 받아서 백엔드로 보내는 로직을 짜보도록 하겠습니다. 

 

우선 router에서 social/kakao페이지를 만들어 줍니다. 

      {
        path: "social",
        children: [
          {
            path: "github",
            element: <GithubConfirm />,
          },
          {
            path: "kakao",
            element: <KakaoConfirm />,
          },
        ],
      },

그리고 파일을 하나만들어  줍니다. 

저는 routes에서 KakaoConfirm라고 만들어 줬습니다. 

import { Heading, Spinner, Text, useToast, VStack } from "@chakra-ui/react";
import { useQueryClient } from "@tanstack/react-query";
import { useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { kakaoLogIn } from "./api";

export default function KakaoConfirm() {
  const toast = useToast(); // 메시지용
  const queryClient = useQueryClient(); //내 정보 캐쉬하기 위해
  const navigate = useNavigate(); // 로그인 되면 어느 화면 보여줄지 정하기 위해 
  // useLocation은 우리가 있는 곳을 알려준다.
  const { search } = useLocation();
  const confirmLogin = async () => {
    const params = new URLSearchParams(search);
    const code = params.get("code");
    if (code) {
      const status = await kakaoLogIn(code); // 카카오에서 보낸 정보를 API를 활용 백엔드로 통신
 
      if (status === 200) { // 200이면 로그인 성공
        toast({
          status: "success",
          title: "Welcome!",
          position: "bottom-right",
          description: "Happy to have you back!",
        });
        queryClient.refetchQueries(["me"]);
        navigate("/");
      }
    }
  };
  useEffect(() => {
    confirmLogin();
  }, []);
  return (
    <VStack justifyContent={"center"} mt={40}>
      <Heading>Processing log in ...</Heading>
      <Text>Don't go anywhere.</Text>
      <Spinner size="lg" />
    </VStack>
  );
}

 

kakaoLogIn  백엔드로 데이터를 보내준다. 


export const kakaoLogIn = (code: string) =>
  instance
    .post(
      `/users/kakao`, // 
      { code },
      {
        headers: {
          "X-CSRFToken": Cookie.get("csrftoken") || "",
        },
      }
    )
    .then((response) => response.status);

 

여기까지 하면 Step1이 끝냈다. 

다음에 django에서 정보를 받아서 처리하면 된다. 

 

 

Step2

이 정보를 받기 위해서는 requests 를 설치해 주어야 한다. 

 

$ python -m pip install requests

 

아래 링크를 참조한다. 

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-token-request

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

예제

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-token-sample

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

코드 완성 예제

class KakaoLogIn(APIView):
    def post(self, request):
        try:
            code = request.data.get("code")
            access_token = requests.post(
                "https://kauth.kakao.com/oauth/token",
                headers={"Content-Type": "application/x-www-form-urlencoded"},
                data={
                    "grant_type": "authorization_code",
                    "client_id": "REST API",
                    "redirect_uri": "http://127.0.0.1:3000/social/kakao",
                    "code": code,
                },
            )

이제 테스트를 해 보면

print(access_token.json())

긴 문자열이 출력 된다면 성공이다. 

 

이제 access_token을 이용하여 유저 정보를 가져 올 차례이다. 

https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

코드 예시

class KakaoLogIn(APIView):
    def post(self, request):
        try:
            code = request.data.get("code")
            access_token = requests.post(
                "https://kauth.kakao.com/oauth/token",
                headers={"Content-Type": "application/x-www-form-urlencoded"},
                data={
                    "grant_type": "authorization_code",
                    "client_id": "REST API",
                    "redirect_uri": "http://127.0.0.1:3000/social/kakao",
                    "code": code,
                },
            )
            access_token = access_token.json().get("access_token")
            user_data = requests.get(
                "https://kapi.kakao.com/v2/user/me",
                headers={
                    "Authorization": f"Bearer {access_token}",
                    "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
                },
            )
            user_data = user_data.json()

그 다음으로는 해당 정보를 이용해 회원가입 후 로그인 혹은 그냥 로그인을 시키면 된다. 

 

예시)

class KakaoLogIn(APIView):
    def post(self, request):
        try:
            code = request.data.get("code")
            access_token = requests.post(
                "https://kauth.kakao.com/oauth/token",
                headers={"Content-Type": "application/x-www-form-urlencoded"},
                data={
                    "grant_type": "authorization_code",
                    "client_id": "REST API",
                    "redirect_uri": "http://127.0.0.1:3000/social/kakao",
                    "code": code,
                },
            )
            access_token = access_token.json().get("access_token")
            user_data = requests.get(
                "https://kapi.kakao.com/v2/user/me",
                headers={
                    "Authorization": f"Bearer {access_token}",
                    "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
                },
            )
            user_data = user_data.json()
            kakao_account = user_data.get("kakao_account")
            profile = kakao_account.get("profile")
            try:
                user = User.objects.get(email=kakao_account.get("email"))
                login(request, user)
                return Response(status=status.HTTP_200_OK)
            except User.DoesNotExist:
                user = User.objects.create(
                    email=kakao_account.get("email"),
                    username=profile.get("nickname"),
                    name=profile.get("nickname"),
                    avatar=profile.get("profile_image_url"),
                )
                user.set_unusable_password()
                user.save()
                login(request, user)
                return Response(status=status.HTTP_200_OK)
        except Exception:
            return Response(status=status.HTTP_400_BAD_REQUEST)

 

'개발' 카테고리의 다른 글

배포된 웹 사이트 새로운 모델 필드 추가하기  (0) 2023.06.19
모델 구조 변경하기  (0) 2023.05.26