Google, Kakao login

GisangLee·2022년 3월 25일
0

my_module

목록 보기
1/33

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"]
        # gender = properties.get("kakao_account").get("gender")
        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)
profile
포폴 및 이력서 : https://gisanglee.github.io/web-porfolio/

0개의 댓글