Skip to content

Commit

Permalink
fix: 카카오 인가코드 전송 시 로그인 가입 후 모든 정보 반환하도록 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
yjoonjang committed Apr 6, 2024
1 parent 37fe8b9 commit 99bd6f2
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 96 deletions.
2 changes: 1 addition & 1 deletion accounts/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class KakaoTokenSerializer(serializers.Serializer):
class UserInfoUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("username", "position", "profile_image")
fields = ("id", "username", "position", "profile_image")


class GetUserInfoSerializer(serializers.ModelSerializer):
Expand Down
3 changes: 1 addition & 2 deletions accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
# TODO swagger에 뜨는 api 관리
urlpatterns = [
path("kakao/", views.kakao_login, name="kakao_login"),
path("kakao/login/", views.kakao_callback, name="kakao_callback"),
path(
"kakao/login/finish/",
"kakao/login/",
views.KakaoLoginView.as_view(),
name="kakao_login_todjango",
),
Expand Down
174 changes: 81 additions & 93 deletions accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@
OpenApiParameter,
)
from django.http import JsonResponse
from rest_framework_simplejwt.tokens import RefreshToken

import requests
from django.shortcuts import redirect
from django.contrib.auth import get_user_model
from json.decoder import JSONDecodeError
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.authtoken.models import Token

from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from dj_rest_auth.registration.views import SocialLoginView
Expand All @@ -42,11 +45,12 @@
env.read_env(env_file)

BASE_URL = env("BASE_URL")
KAKAO_CALLBACK_URI = BASE_URL + "accounts/kakao/login/"
KAKAO_CALLBACK_URI = BASE_URL + "accounts/kakao/callback/"
# KAKAO_CALLBACK_URI = "http://api.resumai.kr/accounts/kakao/callback/"
REST_API_KEY = env("KAKAO_REST_API_KEY")
CLIENT_SECRET = env("KAKAO_CLIENT_SECRET_KEY")

User = get_user_model()

@extend_schema(exclude=True)
def kakao_login(request):
Expand All @@ -55,105 +59,89 @@ def kakao_login(request):
f"https://kauth.kakao.com/oauth/authorize?client_id={REST_API_KEY}&redirect_uri={KAKAO_CALLBACK_URI}&response_type=code"
)

class KakaoLoginView(SocialLoginView):

@extend_schema(
summary="카카오 로그인",
description="code를 GET 요청으로 보내면 access token, code를 반환합니다.",
parameters=[
OpenApiParameter(
name="code", type=str, description="발급받은 카카오의 code 입니다."
),
],
examples=[
OpenApiExample(
response_only=True,
summary="Response Body Example입니다.",
name="success_example",
value={
"access_token": "string",
"code": "string",
@extend_schema(
summary="카카오 로그인 마무리",
description="code (인가 코드)를 post 요청으로 보내면 access token, 유저 정보를 반환합니다. **(id_token은 불필요합니다.)**",
request={
"application/json": {
"type": "object",
"properties": {
"code": {"type": "string"},
},
},
),
],
)
@permission_classes([AllowAny])
@api_view(["GET"])
def kakao_callback(request):
code = request.GET.get("code")
logger.fatal(code)

# Access Token Request
token_req = requests.get(
f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={REST_API_KEY}&client_secret={CLIENT_SECRET}&redirect_uri={KAKAO_CALLBACK_URI}&code={code}"
},
examples=[
OpenApiExample(
response_only=True,
summary="Response Body Example입니다.",
name="success_example",
value={
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0",
"user_info": {
"id": 6,
"email": "[email protected]",
"username": "장영준",
"profile_image": "https://k.kakaocdn.net/dn/cI6qGf/btsCovDyklV/ydaQojxohw6VnLxtcdKwuk/img_640x640.jpg",
"created": False
}
},
),
],
)
def post(self, request, *args, **kwargs):
code = request.data.get("code")
print(code)

token_req_json = token_req.json()
logger.fatal(token_req_json)
if not code:
return Response({"error": "Code is required"}, status=status.HTTP_400_BAD_REQUEST)

error = token_req_json.get("error")
if error is not None:
raise JSONDecodeError(error)
# 카카오 인가코드를 사용해 access_token 획득
token_res = requests.get(f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={REST_API_KEY}&client_secret={CLIENT_SECRET}&redirect_uri={KAKAO_CALLBACK_URI}&code={code}")

if token_res.status_code != 200:
return Response({"error": "Failed to obtain access token"}, status=status.HTTP_400_BAD_REQUEST)

token_json = token_res.json()
access_token = token_json.get("access_token")

# 카카오 access_token으로부터 사용자 정보 획득
headers = {
"Authorization": f"Bearer {access_token}"
}
profile_res = requests.get("https://kapi.kakao.com/v2/user/me", headers=headers)

if profile_res.status_code != 200:
return Response({"error": "Failed to obtain user information"}, status=status.HTTP_400_BAD_REQUEST)

profile_json = profile_res.json()

kakao_oid = profile_json.get("id")
nickname = profile_json.get("properties")["nickname"]
profile_image = profile_json.get("properties")["profile_image"]
email = profile_json.get("kakao_account")["email"]

user, created = User.objects.get_or_create(email=email, defaults={"username": f"{nickname}", "kakao_oid": kakao_oid, "profile_image": f"{profile_image}"})

# 사용자에 대한 토큰 생성
refresh = RefreshToken.for_user(user)
data = {
"access_token": str(refresh.access_token),
"refresh_token": str(refresh),
"user_info": {
"id": user.id,
"email": user.email,
"username": user.username,
"profile_image": user.profile_image,
"is_created": created
}
}

return Response(data, status=status.HTTP_200_OK)

access_token = token_req_json.get("access_token")
logger.fatal(access_token)

# Email Request
profile_request = requests.get(
"https://kapi.kakao.com/v2/user/me",
headers={"Authorization": f"Bearer {access_token}"},
)
profile_data = profile_request.json()

kakao_oid = profile_data.get("id")
kakao_account = profile_data.get("kakao_account")
username = kakao_account["profile"]["nickname"]
profile_image_url = kakao_account["profile"]["profile_image_url"]
email = kakao_account.get("email")

data = {"access_token": access_token, "code": code}
# TODO 유저 프로필 이미지 저장하도록
return JsonResponse(data)


@extend_schema(
summary="카카오 로그인 마무리",
description="access token, code를 post 요청으로 보내면 access token, 유저 정보를 반환합니다. **(id_token은 불필요합니다.)**",
parameters=[
OpenApiParameter(
name="access_token",
type=str,
description="발급받은 카카오의 access_token 입니다.",
),
OpenApiParameter(
name="code", type=str, description="발급받은 카카오의 code 입니다."
),
],
request={
"application/json": {
"type": "object",
"properties": {
"access_token": {"type": "string"},
"code": {"type": "string"},
},
},
},
examples=[
OpenApiExample(
response_only=True,
summary="Response Body Example입니다.",
name="success_example",
value={
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlI",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBl",
"user": {"pk": 6, "email": "[email protected]"},
},
),
],
)
class KakaoLoginView(SocialLoginView):
adapter_class = kakao_view.KakaoOAuth2Adapter
client_class = OAuth2Client
callback_url = KAKAO_CALLBACK_URI


class UpdateUserInfoView(APIView):
Expand Down

0 comments on commit 99bd6f2

Please sign in to comment.