我正在使用AngularJS开发一个SPA应用程序,它使用Django后端作为服务器.我从SPA与服务器通信的方式是使用django-rest-framework.所以现在我想用facebook(google和twitter)进行身份验证,我在这个主题上阅读了很多内容,发现OAuth.io正在客户端SPA端进行验证,而python-social-auth正在做同样的事情但在服务器端.
所以目前我只有客户端身份验证,我的应用程序连接到Facebook(使用OAuth.io)并成功登录.此过程返回access_token然后我向我的API发出请求,该请求必须登录此用户或通过给定令牌为该用户创建帐户,此部分不起作用.所以我不确定我错在哪里,也许是因为没有关于使用python-social-auth的完整教程所以也许我错过了什么或者......我不知道..
所以我的一些代码:
在SPA方面:这是与OAuth.io的连接,并且正在工作,因为我正在获取访问令牌.然后我必须向我的其他API发出请求.后端是'facebook','google'或'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'); }); });
在我的settings.py中的服务器上,我已经为已安装的应用程序,模板上下文预处理器,一些auth后端添加了社交插件,这是我的文件:
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', )
在我的API的views.py中,我有以下内容(我在这里找到):
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
最后我在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[^/]+)/$', views.ObtainAuthToken.as_view()), url(r'^register/(?P [^/]+)/', views.register_by_access_token), ...
每当我尝试执行身份验证时,OAuth.io正在运行,并且返回apq的rqest
详细信息:"无效令牌"
我认为我在python-social-auth的配置中遗漏了一些东西,或者我做错了什么.所以如果有人有想法并希望帮助我会很高兴:)
将以下行添加到ObtainAuthToken类
authentication_classes = ()
并且您的错误{"详细信息":"无效令牌"}将消失.
这就是为什么......
您的请求包含以下标头
Authorization: Token yourAccessToken
但您已在DEFAULT_AUTHENTICATION_CLASSES中定义了rest_framework.authentication.TokenAuthentication.
基于此,Django认为您要在执行令牌时执行令牌身份验证.它失败,因为这是facebook的访问令牌,并且在您的django*_token数据库中不存在,因此无效令牌错误.在您的情况下,您需要做的就是告诉Django不要对此视图使用TokenAuthentication.
FYI
请记住,在执行ObtainAuthToken的post方法之前,您的代码执行已停止,因此可能会遇到更多错误.个人在尝试单步执行代码时遇到错误
'DjangoStrategy' object has no attribute 'backend'
上
backend = request.strategy.backend
并通过改为来解决它
uri = '' strategy = load_strategy(request) backend = load_backend(strategy, backend, uri)
此外,您应该更新您的register_by_access_token函数,因为它不与您引用的博客中的工作代码对齐.博客作者在这里发布了他的最新代码.如果你想用它来与像facebook这样的第三方进行身份验证,你的版本不会将令牌从auth标头中拉出来.
是啊.解决了.设置不正确,您需要添加权限.
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' ] }
和一些关于管道的信息:
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' )