Auteur Facebook avec AngularJS et Django REST Framework
je développe une application SPA avec AngularJS qui utilise Django backend pour le serveur. La façon dont je communique avec le serveur de la SPA est avec django-repos-cadre. Donc maintenant je veux faire authentification avec facebook (google et twitter aussi) et j'ai lu beaucoup sur ce sujet et trouvé OAuth.io ce qui rend l'authentification du côté du client SPA et python-social-auth qui est en train de faire la même chose, mais sur le côté serveur.
donc actuellement je n'ai que le client auth, mon application se connecte à facebook (avec OAuth.io) et se connecter avec succès. Ce processus retourne access_token et ensuite je fais une demande à mon API qui doit se connecter à cet utilisateur ou créer un compte pour cet utilisateur par token donné et cette partie ne fonctionne pas. Donc je ne sais pas où je me trompe, peut-être parce qu'il n'y a pas de tutoriel complet sur l'utilisation de python-social-auth alors peut-être que je manque quelque chose ou.. Je ne sais pas..
Donc un peu de code de ce que j'ai:
Côté SPA: c'est la connexion avec OAuth.io et travaille parce que j'obtiens le jeton d'accès. Alors je dois faire une demande à mon API rest. backend est "facebook", "google" ou "twitter'
OAuth.initialize('my-auth-code-for-oauthio');
OAuth.popup(backend, function(error, result) {
//handle error with error
//use result.access_token in your API request
var token = 'Token ' + result.access_token;
var loginPromise = $http({
method:'POST',
url: 'api-token/login/' + backend + '/',
headers: {'Authorization': token}});
loginPromise.success(function () {
console.log('Succeess');
});
loginPromise.error(function (result) {
console.log('error');
});
});
sur le serveur dans mon settings.py j'ai ajouté le plugin social aux applications installées, préprocesseurs de contexte de template, certains auth backends et c'est mon fichier:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
...,
'rest_framework',
'rest_framework.authtoken',
'api',
'social.apps.django_app.default',
'social'
)
TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.core.context_processors.request",
"django.contrib.messages.context_processors.messages",
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',)
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
)
}
SOCIAL_AUTH_FACEBOOK_KEY = 'key'
SOCIAL_AUTH_FACEBOOK_SECRET = 'secret'
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
AUTHENTICATION_BACKENDS = (
'social.backends.open_id.OpenIdAuth',
'social.backends.facebook.FacebookOAuth2',
'social.backends.facebook.FacebookAppOAuth',
'social.backends.google.GoogleOpenId',
'social.backends.google.GoogleOAuth2',
'social.backends.google.GoogleOAuth',
'social.backends.twitter.TwitterOAuth',
'django.contrib.auth.backends.ModelBackend',
)
Dans mon views.py de l'API, j'ai le texte suivant (je l'ai trouvé ici):
from django.contrib.auth.models import User, Group
from rest_framework import viewsets, generics
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions, parsers, renderers
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.decorators import api_view, throttle_classes
from social.apps.django_app.utils import strategy
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
class ObtainAuthToken(APIView):
throttle_classes = ()
permission_classes = ()
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AuthTokenSerializer
model = Token
# Accept backend as a parameter and 'auth' for a login / pass
def post(self, request, backend):
serializer = self.serializer_class(data=request.DATA)
if backend == 'auth':
if serializer.is_valid():
token, created = Token.objects.get_or_create(user=serializer.object['user'])
return Response({'token': token.key})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
# Here we call PSA to authenticate like we would if we used PSA on server side.
user = register_by_access_token(request, backend)
# If user is active we get or create the REST token and send it back with user data
if user and user.is_active:
token, created = Token.objects.get_or_create(user=user)
return Response({'id': user.id , 'name': user.username, 'userRole': 'user','token': token.key})
@strategy()
def register_by_access_token(request, backend):
backend = request.strategy.backend
user = request.user
user = backend._do_auth(
access_token=request.GET.get('access_token'),
user=user.is_authenticated() and user or None
)
return user
et finalement j'ai ces routes en urls.py:
...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api-token-auth/', 'rest_framework.authtoken.views.obtain_auth_token'),
url(r'^api-token/login/(?P<backend>[^/]+)/$', views.ObtainAuthToken.as_view()),
url(r'^register/(?P<backend>[^/]+)/', views.register_by_access_token),
...
Everytime when I try to do auth, outh.io fonctionne et le rqest renvoie
détails: "Invalid token"
je pense que j'ai manqué quelque chose dans la configuration de python-social-auth ou je fais tout de travers. Je vais donc être heureux si quelqu'un a des idées et qui veulent aider :)
3 réponses
ajouter la ligne suivante à votre classe ObtainAuthToken
authentication_classes = ()
et votre erreur {"detail":" Invalid token"} disparaîtra.
Voici pourquoi...
Votre demande contient l'en-tête suivant
Authorization: Token yourAccessToken
pourtant vous avez défini rest_fram Framework.Authentication.TokenAuthentication in DEFAULT_AUTHENTICATION_CLASSES.
basé sur ce Django pense que vous voulez effectuer une authentification de token Jeton. Il échoue parce qu'il s'agit d'un token d'accès pour facebook et qu'il n'existe pas dans votre base de données django *_token, d'où l'erreur de token invalide. Dans votre cas, tout ce que vous devez faire est de dire à Django de ne pas utiliser TokenAuthentication pour cette vue.
pour information!--11-->
gardez à l'esprit que vous pouvez rencontrer d'autres erreurs car l'exécution de votre code a été interrompue avant l'exécution de la méthode post D'ObtainAuthToken. Personnellement en essayant de passer par votre code j'ai eu l'erreur
'DjangoStrategy' object has no attribute 'backend'
backend = request.strategy.backend
et résolu en changeant
uri = ''
strategy = load_strategy(request)
backend = load_backend(strategy, backend, uri)
en outre, vous devriez mettre à jour votre fonction you register_by_access_token car elle ne correspond pas au code de travail du blog que vous avez mentionné. L'auteur du blog a posté son dernier code ici. Votre version ne retire pas le token de l'en-tête auth qui est requis si vous voulez l'utiliser pour auth avec un tiers comme facebook.
Oui. Résoudre. Les paramètres ne sont pas corrects et vous devez ajouter des permissions.
REST_FRAMEWORK = {
# Use hyperlinked styles by default.
# Only used if the `serializer_class` attribute is not set on a view.
'DEFAULT_MODEL_SERIALIZER_CLASS':
'rest_framework.serializers.HyperlinkedModelSerializer',
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
et quelques informations sur pipeline:
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'social.pipeline.social_auth.associate_by_email',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details'
)
j'utilise des outils comme vous, mais je fournis mon login/enregistrer/.... avec
django-allauth
package, puis utiliser django-rest-auth
pour la manipulation de L'API.
vous avez juste besoin de suivre les instructions d'installation, puis de les utiliser pour vos API de repos.
ajouter allauth
et rest-auth
to your INSTALLED_APPS:
INSTALLED_APPS = (
...,
'rest_framework',
'rest_framework.authtoken',
'rest_auth'
...,
'allauth',
'allauth.account',
'rest_auth.registration',
...,
'allauth.socialaccount',
'allauth.socialaccount.providers.facebook',
)
puis ajoutez vos urls personnalisées:
urlpatterns = patterns('',
...,
(r'^auth/', include('rest_auth.urls')),
(r'^auth/registration/', include('rest_auth.registration.urls'))
)
enfin, ajouter cette ligne:
TEMPLATE_CONTEXT_PROCESSORS = (
...,
'allauth.account.context_processors.account',
'allauth.socialaccount.context_processors.socialaccount',
...
)
Ces deux les paquets fonctionnent comme un charme, et vous n'avez pas besoin de vous soucier de n'importe quel type de login.l'inscription, parce que allauth
package gère à la fois le login django model et le login oAuth.
j'espère que cela aide