[DRF] 구글 소셜 로그인 구현하기 (JWT) (240328 수정)

JinUk Lee·2023년 4월 11일
0

DRF 학습하기

목록 보기
22/57

[DRF] 카카오 소셜 로그인 구현하기 (JWT), 쿠키 설정 및 주의사항 (CORS관련)

전체적인 코드는 카카오 로그인에서 사용한 것과 비슷하다.

#views.py

GOOGLE_CALLBACK_URI = "http://localhost:8080/login"  # 프론트 로그인 URI 입력




GOOGLE_CALLBACK_URI = "http://localhost:8080/login"  # 프론트 로그인 URI 입력

@api_view(["GET", "POST"])
@permission_classes([AllowAny])
def google_callback(request):
    client_id = os.getenv("구글 클라이언트 ID 환경변수")
    client_secret = os.getenv("구글 시크릿키 환경변수")
    code = request.GET.get("code")
    """
    Access Token Request
    """
    state = os.getenv("STATE") # 난수
    token_req = requests.post(
        f"https://oauth2.googleapis.com/token?client_id={client_id}&client_secret={client_secret}&code={code}&grant_type=authorization_code&redirect_uri={GOOGLE_CALLBACK_URI}&state={state}"
    )
    token_req_json = token_req.json()
    error = token_req_json.get("error")
    if error is not None:
        raise JSONDecodeError(error)
    access_token = token_req_json.get("access_token")
    """
    Email Request
    """
    email_req = requests.get(
        f"https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={access_token}"
    )
    email_req_status = email_req.status_code
    if email_req_status != 200:
        return JsonResponse(
            {"err_msg": "failed to get email"}, status=status.HTTP_400_BAD_REQUEST
        )
    email_req_json = email_req.json()
    email = email_req_json.get("email")
    """
    Signup or Signin Request
    """

    cookie_max_age = 3600 * 24 * 14 # 14 days

    try:
        user = User.objects.get(email=email)
        # 기존에 가입된 유저의 Provider가 google이 아니면 에러 발생, 맞으면 로그인
        # 다른 SNS로 가입된 유저
        social_user = SocialAccount.objects.get(user=user)
        if social_user is None:
            return JsonResponse(
                {"err_msg": "email exists but not social user"},
                status=status.HTTP_400_BAD_REQUEST,
            )
        if social_user.provider != "google":
            return JsonResponse(
                {"err_msg": "no matching social type"},
                status=status.HTTP_400_BAD_REQUEST,
            )
        # 기존에 Google로 가입된 유저
        accept = requests.post(f"{BASE_URL}accounts/google/login/finish/", data=token_req_json)
        
        accept_status = accept.status_code
        if accept_status != 200:
            return JsonResponse({"err_msg": "failed to signin"}, status=accept_status)
        accept_json = accept.json()
        refresh_token = accept.headers['Set-Cookie']
        refresh_token = refresh_token.replace('=',';').replace(',',';').split(';')
        token_index = refresh_token.index(' refresh_token')
        refresh_token = refresh_token[token_index+1]
        accept_json.pop("user", None)
        response_cookie = JsonResponse(accept_json)
        response_cookie.set_cookie('refresh_token', refresh_token, max_age=cookie_max_age, httponly=True, samesite='Lax')
        return response_cookie
    
    
    except User.DoesNotExist:
        # 기존에 가입된 유저가 없으면 새로 가입
        accept = requests.post("http://localhost:8000/accounts/google/login/finish/", data=token_req_json)
        accept_status = accept.status_code
        if accept_status != 200:
            return JsonResponse({"err_msg": "failed to signup"}, status=accept_status)
        accept_json = accept.json()
        refresh_token = accept.headers['Set-Cookie']
        refresh_token = refresh_token.replace('=',';').replace(',',';').split(';')
        token_index = refresh_token.index(' refresh_token')
        refresh_token = refresh_token[token_index+1]
        accept_json.pop("user", None)
        response_cookie = JsonResponse(accept_json)
        response_cookie.set_cookie('refresh_token', refresh_token, max_age=cookie_max_age, httponly=True, samesite='Lax')
        return response_cookie

카카오와 아주 조금 다른게 있다면 state 라는 랜덤한 문자열이 필요하다.

state는 csrf 공격을 방지하기 위한 토큰같은 개념이다.

구글 로그인에 필요한 키는 아래의 링크에서 생성할 수 있다.

https://console.cloud.google.com/getting-started?hl=ko


클라이언트 ID와 보안 비밀번호를 받고, 리디렉션 URI에 콜백URI를 입력해주면 된다.


24.03.28 수정

allauth 패키지 업데이트로 인해 코드가 달라져 에러가 발생하는 부분을 발견해서 수정, 보완했다.

profile
개발자 지망생

0개의 댓글

관련 채용 정보