현제의 현재이야기

[OSOD] Django Rest Framework + React Google social login 본문

DRF/OSOD

[OSOD] Django Rest Framework + React Google social login

현재의 현제 2023. 3. 5. 08:37

전에 내가 구현했던 구글 로그인은 drf에서 구글로그인이 진행된 것이기에 혼자 구글로그인창 띄우고 구글로부터 인증을 받아 code를 받고, access token을 받고 북치고 장구치고 다했다.

그렇지만 react, 즉 프론트와의 연결을 시도하면 무수한 오류가 뜸과 더불어서 뭔가 잘 안됐다. 10시간가량 삽질한 결과.. react와 연동할 때는 auth_code 혹은 access_token 자체를 프론트엔드로부터 받아오는 작업을 했어야 됐다. 즉 프론트에서 구글 인증을 시도하고 거기에서 나오는 부산물만 백으로 넘겨서 서버 작업을 진행하는 것이다!

아무리 뒤져도 안나오길래 삽질을 오지게 한 결과.. 은근히 소셜 로그인은 access token만 받아오면 끝나는 간단한 문제여따..

우선 뭐 간단하게 Oauth 구글 계정 설정해주고, admin 들어가서 social provider로 등록을 해준다.

그리고냐서 기존의 코드에서 프론트로부터 access_token을 받아오기만 하면 끝...

class GetGoogleAccessView(APIView):
    def post(self, request, *args, **kwargs):
        access_token = request.data.get("access_token")
        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 Response({'err_msg': 'failed to get email'}, status=status.HTTP_400_BAD_REQUEST)
    
        email_req_json = email_req.json()
        email = email_req_json.get('email')

        try:
            user = User.objects.get(email=email)
            social_user = SocialAccount.objects.get(user=user)
            
            if social_user.provider != 'google':
                return Response({'err_msg': 'no matching social type'}, status=status.HTTP_400_BAD_REQUEST)
            
            if user.is_first:
                user.is_first = False
                user.save(update_fields=['is_first'])

            data = {'access_token': access_token}
            accept = requests.post(f"{BASE_URL}accounts/google/login/finish/", data=data)
            accept_status = accept.status_code
            
            if accept_status != 200:
                return Response({'err_msg': 'failed to signin'}, status=accept_status)

            accept_json = accept.json()
            return Response(accept_json)
        
        except User.DoesNotExist:
            data = {'access_token': access_token}
            
            accept = requests.post(f"{BASE_URL}accounts/google/login/finish/", data=data)
            
            accept_status = accept.status_code

            if accept_status != 200:
                return Response({'err_msg': 'failed to signup'}, status=accept_status)
            accept_json = accept.json()
            
            return Response(accept_json)

        except SocialAccount.DoesNotExist:
            return JsonResponse({'err_msg': 'email exists but not social user'}, status=status.HTTP_400_BAD_REQUEST)
  • 여기에서 requests.post로 access_token을 날리는 엔드포인트의 뷰는 이것이다.
  • 프론트에서부터 request.data.get으로 access_token 값을 얻어온다.
class GoogleLogin(SocialLoginView):
    adapter_class = google_view.GoogleOAuth2Adapter
    permission_classes = [AllowAny]
  • 내가 삽질한 이유가 바로 이 SocialLoginView이다. 왜냐하면 처음에 access token만 넣으면 반응이 없었기 때문이다. 무슨 말이냐 하면

  • 여기서 Code를 받아야 한다길래 어마어마한 뻘짓을 하였다.
  • 하지만 내가 이해를 잘못하고 있었다. code가 있어야 access_token이 나오는 것이지, token이 있어야 로그인이 진행된다는 것은 아니었다.
  • 잘 해결되었으나.. 너무 한 곳에 매몰되지 말고 테스트 할 때도 잘 생각해서 신중히 해야겠다. 그냥 넘어가면 삽질 시간은 더 늘어날 뿐...

Urls.py

 

urlpatterns = [
    # 회원가입
    path('registration/', RegisterView.as_view(), name='rest_register'),
    # 유효한 이메일이 유저에게 전달
    re_path(r'^account-confirm-email/$', CustomVerifyEmailView.as_view(), name='account_email_verification_sent'),
    # 유저가 클릭한 이메일(=링크) 확인
    re_path(r'^account-confirm-email/(?P<key>[-:\w]+)/$', ReceiveConfirmEmailView.as_view(), name='account_confirm_email'),
]
  • 혹시 모르니 url도 첨부!
Comments