Подтвердить что ты не робот

Facebook Auth с AngularJS и Django REST Framework

Я разрабатываю приложение SPA с AngularJS, в котором используется 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 для отдыха. backend - это "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 я добавил социальный плагин к установленным приложениям, препроцессорам контекста шаблона, некоторым резервным серверам и это мой файл:

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',
  )

В моем view.py API у меня есть следующее (я нашел здесь):

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<backend>[^/]+)/$', views.ObtainAuthToken.as_view()),
url(r'^register/(?P<backend>[^/]+)/', views.register_by_access_token),
...

Каждый раз, когда я пытаюсь выполнить auth, OAuth.io работает, а rqest to api возвращает

подробнее: "Недопустимый токен"

Я думаю, что я пропустил что-то в конфигурации python-social-auth, или я делаю все неправильно. Поэтому я буду рад, если у кого есть какие-то идеи и вы хотите помочь:)

4b9b3361

Ответ 1

Добавьте следующую строку в класс ObtainAuthToken

authentication_classes = ()

и ваша ошибка { "detail": "Invalid token" } исчезнет.

Вот почему...

Ваш запрос содержит следующий заголовок

Authorization: Token yourAccessToken

но вы определили rest_framework.authentication.TokenAuthentication в DEFAULT_AUTHENTICATION_CLASSES.

Основываясь на этом Django, вы думаете, что хотите выполнять аутентификацию по токенам, поскольку вы передали токен. Он терпит неудачу, потому что это токен доступа для facebook и не существует в вашей базе данных django * _token, следовательно, недействительная ошибка токена. В вашем случае все, что вам нужно сделать, это указать Django не использовать TokenAuthentication для этого представления.

FYI

Имейте в виду, что вы можете столкнуться с дополнительными ошибками, так как выполнение вашего кода было остановлено до того, как был выполнен метод posttainAuthToken. Лично при попытке выполнить свой код я получил ошибку

'DjangoStrategy' object has no attribute 'backend'

on

backend = request.strategy.backend

и разрешил его, изменив значение на

uri = ''
strategy = load_strategy(request)
backend = load_backend(strategy, backend, uri)

Кроме того, вы должны обновить свою функцию register_by_access_token, поскольку она не соответствует рабочему коду из указанного вами блога. Автор блога опубликовал свой последний код здесь. Ваша версия не вытаскивает токен из заголовка auth, который требуется, если вы хотите использовать его для авторизации с третьей стороной, такой как facebook.

Ответ 2

Да. Решаемые. Настройки неправильные, и вам нужно добавить разрешения.

 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 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'
 )

Ответ 3

Я использую такие инструменты, как вы, но я предоставляю свой логин/регистр/.... с помощью django-allauth, а затем используйте django-rest-auth для Обработка API.

Вам просто нужно следовать инструкциям по установке, а затем использовать их для ваших API-интерфейсов для отдыха.

Добавление allauth и rest-auth к вашему INSTALLED_APPS:

INSTALLED_APPS = (
    ...,
    'rest_framework',
    'rest_framework.authtoken',
    'rest_auth'
    ...,
    'allauth',
    'allauth.account',
    'rest_auth.registration',
    ...,
    'allauth.socialaccount',
    'allauth.socialaccount.providers.facebook',
)

Затем добавьте свои собственные URL-адреса:

urlpatterns = patterns('',
    ...,
    (r'^auth/', include('rest_auth.urls')),
    (r'^auth/registration/', include('rest_auth.registration.urls'))
)

Наконец, добавьте эту строку:

TEMPLATE_CONTEXT_PROCESSORS = (
    ...,
    'allauth.account.context_processors.account',
    'allauth.socialaccount.context_processors.socialaccount',
    ...
)

Эти два пакета работают как шарм, и вам не нужно беспокоиться о любом типе login.registration, потому что пакет allauth обрабатывает имя входа в систему django и имя пользователя oAuth.

Я надеюсь, что это поможет