137

Django とdjango-rest-frameworkを使用して RESTful API を構築しています。

認証メカニズムとして「トークン認証」を選択し、Django-REST-Framework のドキュメントに従って既に実装しています。問題は、アプリケーションがトークンを定期的に更新/変更する必要があるかどうかです。トークンの更新を必要とするのはモバイル アプリであるべきか、それとも Web アプリが自律的に行​​うべきか?

ベストプラクティスは何ですか?

Django REST Framework の経験があり、技術的な解決策を提案できる人はいますか?

(最後の質問は優先度が低くなります)

4

11 に答える 11

122

モバイル クライアントに定期的に認証トークンを更新させることをお勧めします。もちろん、これは強制するサーバー次第です。

デフォルトの TokenAuthentication クラスはこれをサポートしていませんが、拡張してこの機能を実現できます。

例えば:

from rest_framework.authentication import TokenAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed

class ExpiringTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):
        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')

        # This is required for the time comparison
        utc_now = datetime.utcnow()
        utc_now = utc_now.replace(tzinfo=pytz.utc)

        if token.created < utc_now - timedelta(hours=24):
            raise exceptions.AuthenticationFailed('Token has expired')

        return token.user, token

また、ログインが完了するたびにトークンが更新されるように、デフォルトの REST フレームワーク ログイン ビューをオーバーライドする必要があります。

class ObtainExpiringAuthToken(ObtainAuthToken):
    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            token, created =  Token.objects.get_or_create(user=serializer.validated_data['user'])

            if not created:
                # update the created time of the token to keep it valid
                token.created = datetime.datetime.utcnow()
                token.save()

            return Response({'token': token.key})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view()

URL を変更することを忘れないでください。

urlpatterns += patterns(
    '',
    url(r'^users/login/?$', '<path_to_file>.obtain_expiring_auth_token'),
)
于 2013-03-13T08:56:54.827 に答える
6

@odedfos の回答を試しましたが、誤解を招くエラーが発生しました。これは同じ答えで、修正され、適切なインポートが行われています。

views.py

from django.utils import timezone
from rest_framework import status
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken

class ObtainExpiringAuthToken(ObtainAuthToken):
    def post(self, request):
        serializer = self.serializer_class(data=request.DATA)
        if serializer.is_valid():
            token, created =  Token.objects.get_or_create(user=serializer.object['user'])

            if not created:
                # update the created time of the token to keep it valid
                token.created = datetime.datetime.utcnow().replace(tzinfo=utc)
                token.save()

            return Response({'token': token.key})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

authentication.py

from datetime import timedelta
from django.conf import settings
from django.utils import timezone
from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions

EXPIRE_HOURS = getattr(settings, 'REST_FRAMEWORK_TOKEN_EXPIRE_HOURS', 24)

class ExpiringTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):
        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')

        if token.created < timezone.now() - timedelta(hours=EXPIRE_HOURS):
            raise exceptions.AuthenticationFailed('Token has expired')

        return (token.user, token)
于 2013-05-24T16:18:33.863 に答える
4

http://getblimp.github.io/django-rest-framework-jwtを活用できます

このライブラリは、有効期限のあるトークンを生成できます

DRF のデフォルト トークンと DRF によって提供されるトークンの違いを理解するには、以下を参照してください。

Django REST JWT認証を複数のWebサーバーでスケーリングするにはどうすればよいですか?

于 2015-05-09T05:25:47.360 に答える
0

トークンがセッション Cookie のようなものであることに気付いた場合は、Django のセッション Cookie のデフォルトの有効期間をそのまま使用できます: https://docs.djangoproject.com/en/1.4/ref/settings/#session-cookie-age

Django Rest Framework がそれを自動的に処理するかどうかはわかりませんが、古いものを除外して期限切れとしてマークする短いスクリプトをいつでも作成できます。

于 2013-02-18T17:10:06.630 に答える