2015-12-24 13 views
10

Die django-rest-auth-Dokumentation diskutiert die Facebook-Integration, an der ich nicht interessiert bin - mein Anliegen ist das soziale Login über Google. Ich habe das schon seit geraumer Zeit ausprobiert und ich frage mich, ob jemand anderes eine Dokumentation darüber hat, wie sie das gemacht haben ... selbst eine grobe Skizze wäre hilfreich. Bisher habe ich keine Ergebnisse für diese Suche gefunden. Ich bin fast da, kann es aber nicht mit der durchsuchbaren API von Django Rest Framework (DRF) arbeiten lassen.django-rest-auth: social login mit google

Hier ist, was ich bisher habe: Ich begann von dem Demo-Projekt auf der Django-Rest-Auth Github-Seite und modifizierte die Social-Login-Vorlage HTML-Seite nur die Eingabe 'Code', nicht beide 'Code 'UND' Zugriffstoken '. Wenn ich einen gültigen Code (durch eine separate Anfrage an Googles Authentifizierungsendpunkt erhalten) liefern, funktioniert das gut; Die durchsuchbare API rendert die übliche Webseite mit dem "Schlüssel" (das API-Token meiner Anwendung für den Benutzer) in der Antwort. Beim Überprüfen des Django-Admins hat alles funktioniert - der Benutzer ist angemeldet, die E-Mail ist authentifiziert usw. Gut bis jetzt.

Das Problem ist, dass Startpunkt der Bereitstellung des "Code" - und wie bekomme ich diesen Code von Google in erster Linie. Wenn ich das alllauth-Paket zuvor (erfolgreich) benutzt habe, könnte ich einfach auf einen Link klicken, der "unsichtbar" den gesamten OAuth2-Fluss ausführt (dh den Code anfordert, diesen Code verwendet, um das Zugriffstoken zu erhalten und das Zugriffstoken zu verwenden) Nutzer-Google-Konto-Informationen erhalten).

Um diesen nahtlosen Fluss wiederherzustellen (dh NICHT mit dem Code anzufangen), dachte ich, ich könnte den OAuth2-Fluss unterbrechen und den von google zurückgegebenen Code "abfangen" und diesen Code dann an die rest-auth-API für soziale Anmeldung senden . Zu diesem Zweck habe ich eine benutzerdefinierte allauth.socialaccount.providers.oauth2.views.OAuth2CallbackView durch Überschreiben der Versandmethode:

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 

Üblicherweise wird diese Methode aufgerufen wird, wenn Google eine GET-Anforderung an den uri Rückruf sendet zunächst Sie die Google-Auth Endpunkt liefern. Mit dieser Überschreibung kann ich den von google in diesem Rückruf zurückgegebenen Code erfolgreich analysieren. Die POST-Anfrage funktioniert und hat den Schlüssel des Benutzers im Feld resp._content. Es führt jedoch letztendlich nicht dazu, die beabsichtigte Ansicht in der durchsuchbaren DRF-API zu erzeugen.

Basierend auf Tauchen im Callstack, finde ich, dass rest_framework.views.APIView.dispatch ein Objekt des Typs rest_framework.response.Response zurückgibt. Wenn jedoch die oben beschriebene requests.post-Methode abgeschlossen ist, wird eine Instanz des Typs requests.models.Response zurückgegeben. Daher verfügt es nicht über die richtigen Attribute und schlägt in der Django-Middleware fehl. Zum Beispiel hat es keine acceptable_renderer Attribut und keine "Get" -Methode (die in django.middleware.clickjacking.py verwendet wird). Ich könnte, möglicherweise, diese Anforderungen zu der Instanz hinzufügen, aber dann wird dieser Hack noch mehr zu einem Klotz.

Vielen Dank für Ihre Hilfe!

+2

Hast du überall mit diesem bekommen? – jfunk

+0

Leider nicht. Beschäftigt sich mit anderen Dingen und es fiel von meinem Radar. Zum Glück war das kein kritischer Punkt, aber ich bin mir sicher, dass andere daran interessiert sein könnten. –

Antwort

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}) 
Verwandte Themen