1. ホーム
  2. django

[解決済み] RESTful API のトークン認証:トークンは定期的に変更する必要がありますか?

2022-06-10 13:09:32

質問

DjangoでRESTfulなAPIを構築しているのですが、その際に django-rest-framework .

認証メカニズムとして、我々は "Token Authentication" を選択し、Django-REST-Framework のドキュメントに従ってすでに実装しています。トークンの更新を要求するのはモバイルアプリであるべきか、それともウェブアプリが自律的にそれを行うべきなのか?

ベストプラクティスは何でしょうか?

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

(最後の質問の優先順位は低いです)

どのように解決するのですか?

モバイルクライアントに定期的に認証トークンを更新させるのは良い習慣です。もちろん、これを強制するかどうかはサーバー次第です。

デフォルトの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

ログインが行われるたびにトークンがリフレッシュされるように、デフォルトのレストフレームワークのログインビューをオーバーライドすることも必要です。

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