1차 프로젝트때 일반적인 회원가입과 로그인을 해봤으니(물론 제가 안했지만)
2차 때는 소셜로그인 API를 가져와보는 게 어떠냐는 멘토님의 말씀과
저 또한 이번엔 카카오 로그인을 해보고 싶어서 하게 되었습니다.
다만, 찾아보면서 대부분이 나 이렇게 했다식의 자랑이 많아서..
혹여나 보실 분이 계실지 모르지만 상세하게.. 적어보려고 합니다
되도록이면 공식문서 한 번 읽어보고 오시면 더 도움이 될 거라고 생각합니다!
이 그림 카카오 디벨로퍼스에서 많이 보셨을텐데, 백엔드로서 할 건 간단합니다.
프론트엔드에서 토큰을 보내주면, 회원가입을 시켜주던가 기존의 유저 정보를 주던가..!
이게 무슨 말이냐 하면, 당연히 처음에는 어떠한 회원도 없는 빈 DB입니다
하지만 나는 리디북스에 회원가입을 안했지, 카카오톡에는 되어 있기 때문에
받은 토큰을 이용해 카카오톡에 이 토큰을 가진 유저정보를 달라고 요청을 보냅니다.
그러면 카카오에서 리턴해준 정보를 이용해서, 신규 가입을 시켜주던가
이미 가입된 유저면 식별해서 로그인 시켜주면 되는 것입니다.
# 최상위 url
from django.urls import path, include
urlpatterns = [
path('account', include('users.urls')),
path('subscribe', include('subscribes.urls'))
]
#'/account로 들어왔을 때 url conf
from django.urls import path
from users.views import KakaoLoginView
urlpatterns = [
path('/sign-in/kakao', KakaoLoginView.as_view())
]
최종적으로 카카오 로그인을 실행하기 위한 url은
http://localhost:8000/account/sign-in/kakao
가 되었습니다
from django.db import models
from core.models import TimeStampModel
class SocialPlatform(TimeStampModel) :
name = models.CharField(max_length=20)
class Meta :
db_table = 'social_platforms'
class User(TimeStampModel) :
profile_nickname = models.CharField(max_length=40)
profile_image = models.CharField(max_length=500, null=True)
account_email = models.CharField(max_length=40)
social_platform = models.ForeignKey(SocialPlatform, on_delete=models.SET_NULL, null=True)
class Meta :
db_table = 'users'
소셜플랫폼은 나중 리팩토링을 위해 만들었고, 유저정보의 경우
카카오 디벨로퍼스에 나와있는걸 참고하여
프론트엔드 카카오로그인 개발자분과 닉네임/프사/이메일을 받자고 합의하였습니다.
아까 설명했다시피, 프론트로부터 받은 토큰을 이용하여 카카오에 유저정보 요청과
그걸 토대로 회원가입 및 로그인이 이루어지는 과정인데
처음에는 하나의 뷰에서 이 두 과정을 다 작성하였습니다.
그런데, 분리하는 것이 원칙적으로 일반적인 과정이라는 멘토님의 피드백을 받고
수정해보기로 했으며, 그래서 만든 게 kakao_users.py입니다.
이 파일은 프론트로부터 받은 토큰을 이용해 카카오에 유저정보를 요청하기 위해
만들어진 용도입니다.
starapp을 한 파일리스트에서 해당 파일만 추가된 것입니다.
import requests
from django.http import JsonResponse
class KakaoAPI :
def __init__(self, access_token, social_url) :
self.access_token = access_token
self.social_url = social_url
def get_user(self) :
headers = {'Authorization' : f'Bearer {self.access_token}'}
response = requests.get(self.social_url, headers=headers, timeout=3)
if not response.status_code == 200 :
return JsonResponse({'message' : 'Invalid Token'}, status=401)
return response
토큰과 요청을 보낼 url을 받아서 유저정보를 리턴합니다.
카카오 디벨로퍼스에서 HTTP Method, URL, Authorization까지 다 나와서
그대로 따라했습니다.
import jwt
from json.decoder import JSONDecodeError
from django.views import View
from django.http import JsonResponse
from users.models import User
from users.kakao_users import KakaoAPI
from ridibooksl.settings import (
SECRET_KEY,
ALGORITHMS
)
class KakaoLoginView(View):
def post(self, request):
try :
access_token = request.headers.get("Authorization", None)
kakao_user = KakaoAPI(access_token, "https://kapi.kakao.com/v2/user/me")
response = kakao_user.get_user()
if not response.status_code == 200 :
return JsonResponse({'message' : 'Invalid Token'}, status=401)
user_data = response.json()
except KeyError:
return JsonResponse({'message' : 'KEY ERROR'}, status=400)
except JSONDecodeError :
return JsonResponse({'message' : 'JSON DECODE ERROR'}, status=400)
login_user , state = User.objects.get_or_create(
profile_nickname = user_data['properties']['nickname'],
account_email = user_data['kakao_account']['email'],
profile_image = user_data['kakao_account']['profile'].get('profile_image_url', None)
)
new_token = jwt.encode({'user_id' : login_user.id}, SECRET_KEY, ALGORITHMS)
return JsonResponse({'new_token' : new_token, 'user_id': login_user.id}, status = 200)
- 토큰과 URL을 이용하여 kakao_users.py의 KakaoAPI에 유저정보 요청
- 성공적으로 불러오지 못할 시, 토큰에 문제가 있으므로 Invalid Token 에러 발생
- 성공적으로 불러올 시, 유저정보 json형태로 받음
- 예외처리 과정을 모두 뚫었으면 get_or_create를 이용하여 유저정보 불러오던가,
생성하던가 해줌- 'properties', 'kakao_account' 등 이런 것들은 리턴 결과를 보면 알 수 있음
카카오 디벨로퍼스에서 보여준 response예시입니다.
이 정보들이 위의 코드에 있는 user_data에 들어가게 되며,
여기서 원하는 값을 가져와서 get_or_create 해주는 것이죠
HTTP/1.1 200 OK
{
"id":123456789,
"kakao_account": {
"profile_needs_agreement": false,
"profile": {
"nickname": "홍길동",
"thumbnail_image_url": "http://yyy.kakao.com/.../img_110x110.jpg",
"profile_image_url": "http://yyy.kakao.com/dn/.../img_640x640.jpg",
"is_default_image":false
},
"email_needs_agreement":false,
"is_email_valid": true,
"is_email_verified": true,
"email": "sample@sample.com",
"age_range_needs_agreement":false,
"age_range":"20~29",
"birthday_needs_agreement":false,
"birthday":"1130",
"gender_needs_agreement":false,
"gender":"female"
},
"properties":{
"nickname":"홍길동카톡",
"thumbnail_image":"http://xxx.kakao.co.kr/.../aaa.jpg",
"profile_image":"http://xxx.kakao.co.kr/.../bbb.jpg",
"custom_field1":"23",
"custom_field2":"여"
...
}
}