2015-12-24 13 views
10

Dokumentacja django-rest-auth omawia integrację Facebooka, której nie jestem zainteresowany - moją troską jest zapewnienie logowania społecznościowego przez Google. Próbowałem tego już od jakiegoś czasu i zastanawiam się, czy ktoś jeszcze nie ma dokumentacji, jak to zrobili ... nawet pomocny byłby szkic. Do tej pory nie znalazłem żadnych wyników dla tego wyszukiwania. Już prawie jestem, ale nie mogę go uruchomić z interfejsem do przeglądania Django rest Framework (DRF).django-rest-auth: login społecznościowy z google

Oto co mam do tej pory: Zacząłem od projektu demo dostarczonej na stronie django-rest-auth github i zmodyfikowany szablon strony HTML logowania społecznego wymagają jedynie wejście „kodu”, a nie jak „Kod "AND" access_token ". Kiedy dostarczę poprawny kod (uzyskany przez oddzielne żądanie do google's auth punktu końcowego), to działa dobrze; przeglądalny interfejs API renderuje zwykłą stronę internetową za pomocą "klucza" (token API mojej aplikacji dla użytkownika) w odpowiedzi. Sprawdzanie administratora django, wszystko działało - użytkownik jest zalogowany, e-mail jest uwierzytelniony, itp. Dobre jak dotąd.

Kwestia polega na tym, że punktem wyjścia jest dostarczanie "kodu" - i jak ten kod jest pobierany z google. Kiedy poprzednio (z powodzeniem) korzystałem z pakietu allauth, mogłem po prostu kliknąć na link, który "niewidzialnie" wykonałby cały przepływ OAuth2 (tj. Zażądał kodu, użył tego kodu, aby uzyskać token dostępu, i użył tokena dostępu do uzyskać informacje o koncie Google użytkownika).

Aby odtworzyć ten płynny przepływ (tzn. NIE zaczynałem od kodu), doszedłem do wniosku, że mogę przerwać przepływ OAuth2 i "przechwycić" kod zwrócony z google, a następnie wysłać ten kod do interfejsu API społecznościowego z rest-auth . W tym celu stworzyłem zwyczaj allauth.socialaccount.providers.oauth2.views.OAuth2CallbackView poprzez nadpisanie metody wysyłki:

class CustomOAuth2CallbackView(OAuth2CallbackView): 
    def dispatch(self, request): 
     # gets the code correctly: 
     code = request.GET['code'] 

     # rp is of type requests.methods.Response 
     rp = requests.post(<REST-AUTH API ENDPOINT>, data = {'code':code}) 
     return rp 

Zazwyczaj ta metoda jest wywoływana, gdy google wysyła żądanie GET do URI zwrotnego początkowo dostarczyć do firmy google auth końcowego. Dzięki temu zastąpieniu mogę skutecznie przeanalizować kod zwrócony z google w tym wywołaniu zwrotnym. Żądanie POST działa i ma klucz użytkownika w polu resp._content. Ostatecznie jednak nie uda się uzyskać zamierzonego widoku w interfejsie API DRF do przeglądania.

Opierając się na nurkowaniu w stelażu, stwierdzam, że rest_framework.views.APIView.dispatch zwraca obiekt typu rest_framework.response.Response. Jednak po zakończeniu powyższej metody requests.post zwraca ona instancję typu requests.models.Response. W rezultacie nie ma odpowiednich atrybutów i nie działa w oprogramowaniu pośredniczącym django. Na przykład nie ma atrybutu acceptable_renderer i nie ma metody "get" (która jest używana w django.middleware.clickjacking.py). Mogłem, prawdopodobnie, dodać te wymagania do instancji requests.models.Response (rp), ale potem ten hack staje się jeszcze bardziej kludge.

Dzięki za pomoc, jaką możesz zapewnić!

+2

dostałeś nigdzie z tym? – jfunk

+0

Niestety nie. Zajęty innymi rzeczami i spadł z mojego radaru. Na szczęście nie był to element krytyczny, ale jestem pewien, że inni mogliby być tym zainteresowani. –

Odpowiedz

1

https://github.com/st4lk/django-rest-social-auth

class SocialLoginSignup(SocialSessionAuthView): 
""" 
    Mobile user social signup and login api view 

    args: 
     provider: name of the social network 
     access_token: auth token got from the social sites 
""" 
serializer_class = SocialSignUpSerializer 
authentication_classes = (TokenAuthentication,) 

def post(self, request, *args, **kwargs): 
    serializer = self.serializer_class(data=request.data) 
    serializer.is_valid(raise_exception=True) 
    provider_name = serializer.validated_data['provider'] 

    decorate_request(request, provider_name) # assign the provider class object in request 

    authed_user = request.user if not request.user.is_anonymous() else None 

    token = serializer.validated_data['access_token'] 

    if self.oauth_v1() and request.backend.OAUTH_TOKEN_PARAMETER_NAME not in serializer.validated_data: 
     request_token = parse_qs(request.backend.set_unauthorized_token()) 
     return Response(request_token) 

    try: 
     # authentication function get call from assign class object in request 
     user = request.backend.do_auth(token, user=authed_user) 
    except social_exceptions.AuthException as e: 
     raise exceptions.ParseError({'error':str(e)}) 
    except social_exceptions.AuthTokenError as e: 
     raise exceptions.ParseError({'error': str(e)}) 
    except social_exceptions.AuthAlreadyAssociated as e: 
     raise exceptions.ParseError({'error': str(e)}) 
    except social_exceptions.AuthFailed as e: 
     raise exceptions.ParseError({'error':str(e)}) 
    except social_exceptions.AuthUnknownError as e: 
     raise exceptions.ParseError({'error': str(e)}) 
    except social_exceptions.WrongBackend as e: 
     raise exceptions.ParseError({'error':str(e)}) 
    except Exception as e: 
     raise exceptions.ParseError({'error': social_message.INVALID_AUTH_TOKEN}) 

    token, created = Token.objects.get_or_create(user=user) 
    return Response({'auth_token':token.key})