Token Authentication for RESTful API: should the token be periodically changed?

后端 未结 10 1320
庸人自扰
庸人自扰 2020-12-02 03:20

I\'m building a RESTful API with Django and django-rest-framework.

As authentication mechanism we have chosen \"Token Authentication\" and I have already implemented

10条回答
  •  星月不相逢
    2020-12-02 04:00

    It is good practice to have mobile clients periodically renew their authentication token. This of course is up to the server to enforce.

    The default TokenAuthentication class does not support this, however you can extend it to achieve this functionality.

    For example:

    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
    

    It is also required to override the default rest framework login view, so that the token is refreshed whenever a login is done:

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

    And don't forget to modify the urls:

    urlpatterns += patterns(
        '',
        url(r'^users/login/?$', '.obtain_expiring_auth_token'),
    )
    

提交回复
热议问题