web-dev-qa-db-ja.com

AngularJSとDjango RESTフレームワーク)を使用したFacebook認証

サーバーに Django バックエンドを使用する AngularJS を使用してSPAアプリケーションを開発しています。 SPAからサーバーと通信する方法は Django-rest-framework です。だから今私はFacebook(グーグルとツイッターも)で認証をしたいと思っています、そして私はこのトピックについてたくさん読んで、クライアントSPA側で認証を行っている OAuth.io を見つけましたそして python-social-auth これは同じことをしていますが、サーバー側です。

そのため、現在、クライアント認証しかありません。アプリはFacebookに(OAuth.ioを使用して)接続し、正常にログインしています。このプロセスはaccess_tokenを返します。次に、このユーザーにログインするか、指定されたトークンでこのユーザーのアカウントを作成する必要があるAPIにリクエストを送信していますが、この部分は機能していません。ですから、どこが間違っているのかわかりません。おそらくpython-social-authの使用に関する完全なチュートリアルがないため、何かが足りないか、わかりません。

だから私が持っているこれのいくつかのコード:

SPA側:これはOAuth.ioとの接続であり、アクセストークンを取得しているため機能しています。次に、RESTAPIにリクエストを送信する必要があります。バックエンドは「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',
  )

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

Authを実行しようとすると、OAuth.ioが機能し、APIへのrqestが返されます。

詳細:「無効なトークン」

Python-social-authの構成で何かを見逃したか、すべてが間違っていると思います。だから誰かが何かアイデアを持っていて助けたいと思ったら嬉しいです:)

28
valkirilov

次の行をGettainAuthTokenクラスに追加します

authentication_classes = ()

エラー{"detail": "無効なトークン"}はなくなります。

理由は...

リクエストには次のヘッダーが含まれています

Authorization: Token yourAccessToken

それでも、DEFAULT_AUTHENTICATION_CLASSESでrest_framework.authentication.TokenAuthenticationを定義しました。

これに基づいてDjangoは、トークンを渡したときにトークン認証を実行したいと考えています。これはFacebookのアクセストークンであり、Django * _tokenデータベース、したがって無効なトークンエラー。あなたの場合、あなたがする必要があるのは、このビューにTokenAuthenticationを使用しないようにDjangoに伝えることだけです。

[〜#〜] fyi [〜#〜]

GetsAuthTokenの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のようなサードパーティとの認証にトークンを使用する場合に必要な認証ヘッダーからトークンを引き出しません。

7
Steven

うん。解決しました。設定が正しくないため、権限を追加する必要があります。

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

私はあなたと同じようにツールを使用していますが、login/register/....に Django-allauth パッケージを提供してから、 Django-rest-auth を使用します。 = API処理用。

インストール手順に従うだけで、残りのAPIに使用できます。

INSTALLED_APPSにallauthrest-authを追加します。

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

これらの2つのパッケージは魅力のように機能し、allauthパッケージはDjangoモデルログインとoAuthログインの両方を処理するため、login.registrationのタイプについて心配する必要はありません。

お役に立てば幸いです

2
Moe Far