[Django]-Why does Django REST Framework provide different Authentication mechanisms

18👍

Django Rest Framework does not perform authentication in middleware by default for the same reason that Django does not perform authentication in middleware by default: middleware applies to ALL views, and is overkill when you only want to authenticate access to a small portion of your views. Also, having the ability to provide different authentication methods for different API endpoints is a very handy feature.

Rest Framework’s authentication methods do not rely on the Django authentication backend because the Django’s backend is optimised for the common case, and is intimitely linked to the user model. Rest Framework aims to make it easy to:

  1. Use many different authentication methods. (You want HMAC based authentication? done! This is not possible with django auth framework)
  2. Serve API data without ever needing a database behind it. (You have a redis database with all your data in-memory? Serve it in milliseconds without ever waiting for a round trip to DB user model.)
👤Thomas

1👍

Thomas’ answer explains the why quite well. My answer deals more with what you can do about it. I also have a middleware class that determines the current user. I need this because we have some automatic processes (cron) and I want to attribute these to a super user, and I have some model functions that don’t have access to the request object but need to know who the current user is for various functions. So this created some issues as you noticed when we added an API via the REST framework. Here’s my solution (yours will need to be adjusted to your use case):

from threading import local

_user = local()     # thread-safe storage for current user used by middleware below

class CurrentUserMiddleware(object):
    """ Defines Middleware for storing the currently active user """

    def process_request(self, request):
        if not request:
            # Clear the current user if also clearing the request.
            _user.value = 1  # One represents automatic actions done by super admin

        else:
            _user.value = request.user

            if not _user.value or not _user.value.is_authenticated:
                try:
                    authenticator = TokenAuthentication()
                    auth = authenticator.authenticate(request)

                    if auth:
                        _user.value = auth[0]
                except Exception as e:
                    pass

    def process_response(self, request, response):
        _user.value = None

        return response

The authenticator bit deals with seeing if the request has been authenticated by the REST Framework and getting the user.

Leave a comment