2015-12-24 12 views
10

La documentazione di django-rest-auth parla dell'integrazione di Facebook, cosa a cui non sono interessato: la mia preoccupazione è fornire l'accesso social tramite Google. Ho provato questo per un po 'di tempo e mi chiedo se qualcun altro ha alcuna documentazione su come hanno fatto questo ... anche solo uno schizzo preliminare sarebbe utile. Finora, non ho trovato alcun risultato per questa ricerca. Sono quasi arrivato, ma non riesco a farlo funzionare con l'API navigabile Django rest framework (DRF).django-rest-auth: accesso social con google

Ecco quello che ho finora: Ho iniziato dal progetto demo in dotazione sulla pagina django-resto-auth github e modificato il modello di pagina HTML login sociale a richiedere solo l'ingresso 'codice', non sia il codice ' 'AND' access_token '. Quando fornisco un codice valido (ottenuto da una richiesta separata per l'endpoint auth di google), questo funziona correttamente; l'API navigabile esegue il rendering della solita pagina Web con la "chiave" (token API della mia applicazione per l'utente) nella risposta. Controllando l'amministratore di django, tutto ha funzionato: l'utente ha effettuato l'accesso, l'email è autenticata, ecc. Bene finora.

Il problema è che il punto di partenza di fornire il "codice" - e come ottengo quel codice da Google in primo luogo. Quando ho usato (con successo) il pacchetto allauth in precedenza, potevo semplicemente fare clic su un link, che avrebbe "invisibilmente" eseguito l'intero flusso OAuth2 (cioè richiedere il codice, utilizzare quel codice per ottenere il token di accesso e utilizzare il token di accesso per ottieni informazioni sull'account google dell'utente).

Per ricreare il flusso continuo (cioè NON iniziando con il codice), ho pensato che potevo interrompere il flusso di OAuth2 e "intercettare" il codice restituito da google e quindi postare quel codice all'API di login social resto-auth . A tal fine, ho creato una consuetudine allauth.socialaccount.providers.oauth2.views.OAuth2CallbackView sovrascrivendo il metodo di spedizione:

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 

Di solito, questo metodo viene chiamato quando Google invia una richiesta GET al uri richiamata inizialmente fornite al punto finale di autenticazione di Google. Con questo override, sono in grado di analizzare correttamente il codice restituito da google in tale callback. La richiesta POST funziona e ha la chiave dell'utente nel campo resp._content. Tuttavia, alla fine non riesce a produrre la vista desiderata nell'API navigabile DRF.

In base all'immersione nel blocco chiamate, trovo che rest_framework.views.APIView.dispatch restituisce un oggetto di tipo rest_framework.response.Response. Tuttavia, quando viene completato il metodo requests.post sopra, viene restituita un'istanza di tipo requests.models.Response. Di conseguenza, non ha gli attributi corretti e fallisce nel middleware django. Ad esempio, non ha alcun attributo acceptable_renderer e nessun metodo 'get' (utilizzato in django.middleware.clickjacking.py). Potrei, teoricamente, aggiungere questi requisiti all'istanza requests.models.Response (rp), ma poi questo hack diventa ancora più di un kludge.

Grazie per l'aiuto che puoi fornire!

+2

hai preso da nessuna parte con questo? – jfunk

+0

Purtroppo no. Sono stato occupato con altre cose e è caduto dal mio radar. Fortunatamente non era un elemento critico, ma sono sicuro che altri potrebbero essere interessati a questo. –

risposta

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}) 
Problemi correlati