본문 바로가기
Web developer/Django

[Django] 카카오 로그인

by doongjun 2020. 12. 24.

이번 포스팅에서는 장고 카카오 로그인을 구현해보려고 한다.


카카오 로그인은 카카오계정과 애플리케이션을 연결하고 토큰을 발급받아 카카오 API를 사용할 수 있도록 하는 기능이다.

 

카카오 로그인은 Kakao SDK for Android, iOS, JavaScript와 REST API로 제공되며 OAuth 2.0 기반이다.

 

카카오 로그인 진행 과정

 

 

아래 링크에 접속

developers.kakao.com/

 

Kakao Developers

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

developers.kakao.com

내 어플리케이션 > 어플리케이션 추가하기

 

 

위의 폼을 입력하면 어플리케이션이 추가된 것을 확인할 수 있다.

 

아래와 같이 앱 키를 확인할 수 있는데 REST API 키를 복사해준다.

 

 

 

나는 환경변수 파일에 KAKAO_ID라는 이름으로 지정해주었다.

 

내 어플리케이션 > 제품설정 > 카카오 로그인에서 카카오 로그인 API를 활성화해야 서비스를 사용할 수 있다.

또, 아래와 같이 Redirect URI를 설정해준다.

※ 동의항목에서 여러 항목중 필요한 항목들도 설정

 

 

 

설정 완료 하고 나서, users/views.py에 아래와 같이 kakao_login함수를 정의한다.

카카오 로그인 request를 보내면, redirect 되어서 아래 주소로 가게 된다.

client_id는 환경변수 파일에서 설정해 준 REST API 키이고,  REDIRECT_URI는 위와 같이 설정해준다.

※ urls.py에 경로 추가해줘야 함

def kakao_login(request):
    client_id = os.environ.get("KAKAO_ID")
    REDIRECT_URI = "http://127.0.0.1:8000/users/login/kakao/callback"
    return redirect(
        f"https://kauth.kakao.com/oauth/authorize?client_id={client_id}&redirect_uri={REDIRECT_URI}&response_type=code"
    )
def kakao_callback(request):
    try:
    	#(1)
        code = request.GET.get("code")
        client_id = os.environ.get("KAKAO_ID")
        REDIRECT_URI = "http://127.0.0.1:8000/users/login/kakao/callback"
        #(2)
        token_request = requests.get(
            f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={client_id}&redirect_uri={REDIRECT_URI}&code={code}"
        )
        #(3)
        token_json = token_request.json()
        error = token_json.get("error", None)
        if error is not None:
            raise KakaoException()
        #(4)
        access_token = token_json.get("access_token")
        #(5)
        profile_request = requests.get(
            "https://kapi.kakao.com/v2/user/me",
            headers={"Authorization": f"Bearer {access_token}"},
        )
        profile_json = profile_request.json()
        #(6)
        email = profile_json.get("kakao_account", None).get("email")
        if email is None:
            raise KakaoException()
        properties = profile_json.get("properties")
        nickname = properties.get("nickname")
        profile_image = properties.get("profile_image")
        #(7)
        try:
            user = models.User.objects.get(email=email)
            if user.login_method != models.User.LOGIN_KAKAO:
                raise KakaoException()
        except models.User.DoesNotExist:
            user = models.User.objects.create(
                email=email,
                username=email,
                first_name=nickname,
                login_method=models.User.LOGIN_KAKAO,
                email_verified=True,
            )
            user.set_unusable_password()
            user.save()
            #(8)
            if profile_image is not None:
                photo_request = requests.get(profile_image)
                user.avatar.save(
                    f"{nickname}-avatar", ContentFile(photo_request.content)
                )
        login(request, user)
        return redirect(reverse("core:home"))
    except KakaoException:
        return redirect(reverse("users:login"))

(1) kakao_login에서 request를 보내면, url의 code 값을 알아낼 수 있다.

(2) code를 얻었다면, kauth.kakao.com/oauth/token으로 POST를 한다.

(3) JSON을 얻는다.

(4) access_token을 얻는다.

(5) kapi.kakao.com/v2/user/me 으로 access_token을 보내고 profile_json을 받아온다.

※ profile_request.json() 에는 아래와 같은 속성을 갖고 있다.

 

 

 

(6) profile_request.json()으로 부터 email, nickname, profile_image등을 받아온다.

(7) 모델에 추가

(8) 프로필 이미지를 받아오는데, 이미지 URL이 나오지 않고 avatar파일로 저장하기 위함이다.

※ profile image URL이 나오는 것보다 더 좋은 방법이다. 만약 kakao 파일 구조가 변경되거나, 파일 이름이 바뀌면 avatar가 깨질 위험이 있다. 또 kakao로 로그인을 했지만 avatar를 바꾸고 싶을 수도 있기 때문에 (8)과 같은 방식이 더 좋은 방법이다.

 

참고 문헌

developers.kakao.com/docs

 

Kakao Developers

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

developers.kakao.com

위 링크에 들어가보면 더 많은 정보를 얻을 수 있다.

댓글