简体   繁体   中英

How to return 401 when Auth Token is missing in Django Rest Framework

I'm finding hard to figure out how to return 401 when the token has been deleted in database for whatever reason.

Let me explain.

My general settings use SessionAuthentication and TokenAuthentication schemes.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_FILTER_BACKENDS': (
        'rest_framework.filters.DjangoFilterBackend',
    ),
    'DATETIME_FORMAT': '%a, %d %b %Y %H:%M:%S %z',
    'DATETIME_INPUT_FORMATS': ['iso-8601', '%Y-%m-%d %H:%M:%S', '%a, %d %b %Y %H:%M:%S %z'],
    'DATE_FORMAT': '%Y-%m-%d',
    'DATE_INPUT_FORMATS': ['%Y-%m-%d', '%m/%d/%YYYY'],
    'PAGE_SIZE': 20
}

I have a view for generating the Auth Token, like this:

class AcmeObtainAuthToken(APIView):
    throttle_classes = ()
    permission_classes = ()
    parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
    renderer_classes = (renderers.JSONRenderer,)
    serializer_class = AcmeAuthTokenSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data)
        serializer.context = {'request': self.request}
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
       return Response({'token': token.key,
                     'school': school,
                     'user': user.id})

obtain_auth_token = AcmeObtainAuthToken.as_view()

My problem is that when token stored in db is gone for whatever reason and clients send the token, I'm getting 403, when I require 401.

Looking at the docs this is really cryptic:

The kind of response that will be used depends on the authentication scheme. Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. The first authentication class set on the view is used when determining the type of response.

It says it depends but how? No example is given...kinda confusing on how DRF does its magic under the hood here...

403 is the response you should get in that instance. Have a look at this link :

The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated.

In essence, the client made a correct request but the token is missing, therefore his access is forbidden (403).

If you really want to respond with a 401 error, you can try something like the following in your BloowatchObtainAuthToken view:

class BloowatchObtainAuthToken(ObtainAuthToken):
    def post(self, request, *args, **kwargs):
        response = super(BloowatchObtainAuthToken, self).post(request, *args, **kwargs)
        try:
            token = Token.objects.get(user=request.user) # or what you are validating against
            other stuff here...
        except Token.DoesNotExist:
            return Response({'error': 'Token does not exist'}, status=401)

We can overwirte exception_handler of restframework

In your authenticate function:

msg = 'Token not valid'
raise exceptions.AuthenticationFailed(msg)

In your overwrite:

from rest_framework.views import exception_handler
def core_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if response is not None:
        detail = []
        for field, value in response.data.items():
            if isinstance(value, list):
                detail += value
            else:
                detail.append(value)
        response.data['detail'] = ' '.join(detail)
        if response.data['detail'] == 'Token not valid':
            response.status_code = 401



The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM