카카오 로그인 API를 이용해서 소셜 로그인을 구현해보았다.
소셜 로그인 과정은 아래와 같다.
- 유저가 카카오 로그인을 통해 인증코드를 받아 프론트로 전달한다.
- 프론트단에서 인증코드를 카카오 서버로 보내 카카오 토큰을 받아 백엔드 단으로 전달한다.
- 백엔드에서 토큰을 받아 다시 카카오 서버로 보내 유저 정보를 받아온다.
- 해당 유저 정보가 DB에 있는지 확인 후, 서버 토큰을 프론트에 전달한다.
고려한 점
- 유저의 생년월일을 저장해두려고 했는데, 기본적으로 월,일만 제공했다.
string으로 받는 것 보다 date 형식으로 보관하는게 확장성이 좋을 것 같다는 생각에 받은 데이터를 파싱해서 2000-월-일로 DB에 저장하기로 했다.- 로그인할 때마다, 변경된 프로필 사진, 이름 등 DB 업데이트 필요
- 별도의 회원가입 페이지를 만들지 않을 계획이므로 get_or_create 사용
피드백
- requests.get을 이용할 때는 timeout을 지정해두는 것이 좋다.
- 테스트 코드 작성에 관한 피드백은 다음 게시물에서 다뤄볼 예정이다.
코드
import json
import jwt
import requests
from datetime import datetime
from django.http import JsonResponse
from django.views import View
from .models import User
from my_settings import SECRET_KEY
class KakaoSigninView(View):
def get(self, request):
try:
access_token = request.headers.get("Authorization")
if not access_token:
return JsonResponse({"message" : "NEED_TOKEN"}, status = 400)
response = requests.get(
"https://kapi.kakao.com/v2/user/me",
headers = {"Authorization" : f"Bearer {access_token}"},
timeout = 5
)
if not response.status == 200:
raise ConnectionError
profile_json = response.json()
kakao_id = profile_json.get("id")
kakao_account = profile_json.get("kakao_account")
name = kakao_account["profile"]["nickname"]
thumbnail = kakao_account["profile"]["thumbnail_image_url"]
month = kakao_account["birthday"][0:2]
day = kakao_account["birthday"][2:4]
birthday = datetime.strptime(f"2000-{month}-{day}", "%Y-%m-%d").date() if kakao_account["birthday_needs_agreement"] else None
user, created = User.objects.get_or_create(
kakao = kakao_id,
defaults = {
"name" : name,
"thumbnail" : thumbnail,
"birthday" : "birthday",
"is_host" : False
})
user.name = name
user.thumbnail = thumbnail
user.birthday = birthday
user.save()
token = jwt.encode({"id" : user.id}, SECRET_KEY, algorithm = "HS256")
return JsonResponse({"message" : "SUCCESS", "token" : token}, status = 200)
except KeyError:
return JsonResponse({"message" : "KEY_ERROR"}, status = 400)
except ConnectionError:
return JsonResponse({"message" : "KAKAO_ERROR"}, status = 408)