Kakao Login
"""
카카오 SNS 로그인 API
"""
class KakaoLoginView(APIView):
permission_classes = [
customPermission
]
def get(self, request):
REST_API_KEY = os.environ.get("KAKAO_REST_API_KEY")
local_callback_uri = "http://127.0.0.1:8000/api-v1/accounts/login/kakao/callback"
redirect_uri = f"kauth.kakao.com/oauth/authorize?client_id={REST_API_KEY}&redirect_uri={local_callback_uri}&response_type=code&prompt=login"
return redirect(f"https://{redirect_uri}")
class KakaoCallBackView(APIView):
permission_classes = [
customPermission
]
def get(self, request):
REST_API_KEY = os.environ.get("KAKAO_REST_API_KEY")
local_callback_uri = "http://127.0.0.1:8000/api-v1/accounts/login/kakao/callback"
code = request.GET.get("code")
token_request = requests.get(
f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={REST_API_KEY}&redirect_uri={local_callback_uri}&code={code}"
)
token_response_json = token_request.json()
access_token = token_response_json.get("access_token")
profile_request = requests.get(
f"https://kapi.kakao.com/v2/user/me",
headers={"Authorization": f"Bearer {access_token}"},
)
profile_json = profile_request.json()
email = profile_json.get("kakao_account").get("email", None)
properties = profile_json.get("properties")
username = properties["nickname"]
profile_image = profile_json.get("kakao_account")
profile_image = profile_image.get("profile").get("profile_image_url")
try:
user = user_models.User.objects.prefetch_related("profile", "quit_users").get(email=email)
if user:
if not user.is_quit and user.login_method == user_models.User.LOGIN_KAKAO:
payload = {"user_id": user.id}
jwt_token = tokens.generate_jwt_token(payload, "access")
response = {
"message": "카카오 계정으로 로그인 되었습니다.",
"jwt_token": jwt_token,
"kakao_access_token": access_token,
"user": user.username,
}
update_last_login(None, user)
return Response(response, status=status.HTTP_200_OK)
elif not user.is_quit and user.login_method != user_models.User.LOGIN_KAKAO:
response = {
"message": f"{user.login_method} 계정으로 이미 존재하는 계정입니다.",
}
return Response(response, status=status.HTTP_200_OK)
except user_models.User.DoesNotExist:
user = user_models.User.objects.create(email=email, username=username)
user.login_method = "카카오"
user.email_verified = True
user.pwd_change_date = datetime.datetime.now()
user.set_unusable_password()
user.save()
if profile_image is not None:
avatar = requests.get(profile_image)
user_profile = user_models.UserProfile.objects.create(user=user)
user_profile.avatar.save(
f"{username}-avatar", ContentFile(avatar.content)
)
payload = {"user_id": user.id}
jwt_token = tokens.generate_jwt_token(payload, "access")
response = {
"message": "카카오 계정으로 회원가입이 되었습니다.",
"jwt_token": jwt_token,
"kakao_access_token": access_token,
"user": user.username,
}
update_last_login(None, user)
return Response(response, status=status.HTTP_200_OK)
Google Login
class GoogleLoginView(APIView):
permission_classes = [
customPermission
]
def get(self, request):
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_REST_API_KEY")
local_callback_uri = "http://127.0.0.1:8000/accounts/login/google/callback"
google_auth_api = "https://accounts.google.com/o/oauth2/v2/auth"
scope = (
"https://www.googleapis.com/auth/userinfo.email "
+ "https://www.googleapis.com/auth/userinfo.profile"
)
redirect_uri = f"{google_auth_api}?client_id={GOOGLE_CLIENT_ID}&response_type=code&redirect_uri={local_callback_uri}&scope={scope}"
return redirect(redirect_uri)
class GoogleCallbackView(APIView):
permission_classes = [
customPermission
]
def get(self, request):
code = request.GET.get("code")
google_token_api = "https://oauth2.googleapis.com/token"
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_REST_API_KEY")
GOOGLE_SECRET = os.environ.get("GOOGLE_SECRET_PASSWORD")
local_callback_uri = "http://127.0.0.1:8000/accounts/login/google/callback"
state = "random_string"
grant_type = "authorization_code"
google_token_api += f"?client_id={GOOGLE_CLIENT_ID}&client_secret={GOOGLE_SECRET}&code={code}&grant_type={grant_type}&&redirect_uri={local_callback_uri}&state={state}"
token_response = requests.post(google_token_api)
if not token_response.ok:
raise ValueError("google_token is invalid")
access_token = token_response.json().get("access_token")
user_info = requests.get(
"https://www.googleapis.com/oauth2/v3/userinfo",
params={"access_token": access_token},
)
if not user_info.ok:
raise ValueError("사용자 정보를 불러오는데 실패했습니다.")
user_info_json = user_info.json()
profile = {
"username": user_info_json.get("name"),
"email": user_info_json["email"],
"avatar": user_info_json.get("picture"),
"email_verified": user_info_json.get("email_verified"),
}
try:
user = user_models.User.objects.prefetch_related("profile", "quit_users").get(email=profile["email"])
if not user.is_quit and user.login_method == user_models.User.LOGIN_GOOGLE:
payload = {"user_id": user.id}
jwt_token = tokens.generate_jwt_token(payload, "access")
response = {
"message": "구글 계정으로 로그인 되었습니다.",
"jwt_token": jwt_token,
"user": user.username,
}
update_last_login(None, user)
return Response(response, status=status.HTTP_200_OK)
elif not user.is_quit and user.login_method != user_models.User.LOGIN_GOOGLE:
response = {
"message": f"{user.login_method} 계정으로 이미 존재하는 계정입니다.",
}
return Response(response, status=status.HTTP_200_OK)
except user_models.User.DoesNotExist:
user = user_models.User.objects.create(
email=profile["email"], username=profile["username"]
)
if profile["avatar"] is not None:
avatar = requests.get(profile["avatar"])
user_profile = user_models.UserProfile.objects.create(user=user)
user_profile.avatar.save(
f"{profile['username']}-avatar", ContentFile(avatar.content)
)
payload = {"user_id": user.id}
user.login_method = "구글"
user.email_verified = profile["email_verified"]
user.pwd_change_date = datetime.datetime.now()
user.set_unusable_password()
user.save()
jwt_token = tokens.generate_jwt_token(payload, "access")
response = {
"message": "구글 계정으로 회원가입이 되었습니다.",
"jwt_token": jwt_token,
"user": user.username,
}
update_last_login(None, user)
return Response(response, status=status.HTTP_200_OK)