로직은 구글 소셜로그인이랑 진짜 똑같다. 한번 해봤으니까 이론적인 것도 한번 정리해보려고 한다. (카카오 공식문서에 잘 설명돼있길래 겸사겸사)
카카오 개발자 애플리케이션에서 애플리케이션을 추가한다.
내 애플리케이션 > 제품설정 > 카카오 로그인
으로 가서 활성화 설정을 ON으로 바꿔준다.
redirect URI를 등록하고, (콜백함수 url)
내 애플리케이션 > 제품설정 > 카카오 로그인 > 동의항목
으로 가서 카카오 로그인으로 서비스를 시작할 때 동의 받는 항목을 설정한다.
다른 기타 라이브러리 설치나 settings.py는 구글 소셜로그인 포스팅이랑 동일
# settings.py
INSTALLED_APPS = [
...
'allauth.socialaccount.providers.kakao',
]
# .env
SOCIAL_AUTH_KAKAO_CLIENT_ID = "내 앱의 REST API 키"
SOCIAL_AUTH_KAKAO_SECRET = "앱 ID"
admin 페이지에서 카카오 ID, 시크릿 키를 등록한다.
이제 코드를 쓸 시간인데 그 전에 이거부터 보자.
요약버전
이 순서에 맞춰서 코드를 설명하도록 하겠당.
KAKAO_CALLBACK_URI = BASE_URL + 'api/user/kakao/callback/'
def kakao_login(request):
client_id = os.environ.get("SOCIAL_AUTH_KAKAO_CLIENT_ID")
return redirect(f"https://kauth.kakao.com/oauth/authorize?client_id={client_id}&redirect_uri={KAKAO_CALLBACK_URI}&response_type=code&scope=account_email")
카카오 로그인창을 띄우고, 사용자가 카카오 계정으로 로그인을 하면 인증 코드를 받아오는 함수다. 맨 뒤에 scope=account_email
은 추가 항목 동의 받기를 위한 부분인데, 서비스에 회원가입하려면 이메일이 꼭 필요한데 이메일은 제공 동의를 해줘야 받아올 수 있는 정보이기 때문에(심지어 카카오톡 일정 버전부터는 이메일 없이도 카카오 계정 생성이 된다고 한다....) 이메일 동의를 받기 위해 넣은 것이다.
def kakao_callback(request):
client_id = os.environ.get("SOCIAL_AUTH_KAKAO_CLIENT_ID")
code = request.GET.get("code")
# code로 access token 요청
token_request = requests.get(f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={client_id}&redirect_uri={KAKAO_CALLBACK_URI}&code={code}")
token_response_json = token_request.json()
# 에러 발생 시 중단
error = token_response_json.get("error", None)
if error is not None:
raise JSONDecodeError(error)
access_token = token_response_json.get("access_token")
...
위에서 받아온 인증 코드로 access token을 받아온다.
def kakao_callback(request):
...
# access token으로 카카오톡 프로필 요청
profile_request = requests.post(
"https://kapi.kakao.com/v2/user/me",
headers={"Authorization": f"Bearer {access_token}"},
)
profile_json = profile_request.json()
kakao_account = profile_json.get("kakao_account")
email = kakao_account.get("email", None) # 이메일!
# 이메일 없으면 오류 => 카카오톡 최신 버전에서는 이메일 없이 가입 가능해서 추후 수정해야함
if email is None:
return JsonResponse({'err_msg': 'failed to get email'}, status=status.HTTP_400_BAD_REQUEST)
...
앞에서 받아온 access token으로 카카오 사용자 프로필을 받아와서 이메일을 뽑아낸다. 추출해낸 이메일로 서비스에 회원가입/로그인/jwt토큰 발급하는 코드는 구글 소셜로그인과 동일.
참고로 카카오 프로필은 다음과 같은 형태로 받아와진다. (사용자가 이메일 동의항목에 동의하지 않은 경우)
{
"id": 1633204891,
"connected_at": "2021-02-18T06:13:55Z",
"properties": {
"${CUSTOM_PROPERTY_KEY}": "${CUSTOM_PROPERTY_VALUE}",
...
},
"kakao_account": {
"profile_needs_agreement": false,
"profile": {
"nickname": "춘식이",
"thumbnail_image_url": "http://k.kakaocdn.net/dn/DCjQu/btqti3A1gEc/zgip1O4JmSnG7CDfmKtTO2/img_110x110.jpg",
"profile_image_url": "http://k.kakaocdn.net/dn/DCjQu/btqti3A1gEc/zgip1O4JmSnG7CDfmKtTO2/img_640x640.jpg",
"is_default_image": false
},
"email_needs_agreement": true // 이메일 동의 항목에 사용자 동의 필요
}
}
email_needs_agreement
가 true
라는 것은 사용자가 동의하면 이메일 정보를 받을 수 있는 상태를 의미하는 것으로, (❗이메일을 주겠다는 뜻이 아님❗) 위에서 서술한 추가 항목 동의 받기를 통해 이메일 동의 항목에 동의를 해야 우리가 원하는 이메일주소를 포함한 "email"
항목이 하나 더 온다.
from dj_rest_auth.registration.views import SocialLoginView
from allauth.socialaccount.providers.kakao import views as kakao_view
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
class KakaoLogin(SocialLoginView):
adapter_class = kakao_view.KakaoOAuth2Adapter
callback_url = KAKAO_CALLBACK_URI
client_class = OAuth2Client
# urls.py
urlpatterns = [
path('kakao/login', kakao_login, name='kakao_login'),
path('kakao/callback/', kakao_callback, name='kakao_callback'),
path('kakao/login/finish/', KakaoLogin.as_view(), name='kakao_login_todjango'),
]
http://127.0.0.1:8000/api/user/kakao/login
접속
로그인하면 jwt 토큰들이 발급됨
유저도 잘 만들어짐
Authorization도 잘됨
[Django] Django REST framework(DRF) 환경에서 소셜 로그인(kakao) 구현하기 - 1)
[Django] Django REST framework(DRF) 환경에서 소셜 로그인(kakao) 구현하기 - 2)
kakao developers 카카오 로그인 공식문서
if error is not None:
raise JSONDecodeError(error)
이 부분에서 JSONDecodeError, missing 2 required positional arguments 'doc' and 'pos' 라고 에러가 발생하는데 어떻게 해야할까요?