Django and Middleware which uses request.user is always Anonymous

The accepted answer only takes TokenAuthentication in consideration - in my case, there are more authentication methods configured. I thus went with initializing the DRF's Request directly which invokes DRF's authentication machinery and loops through all configured authentication methods.

Unfortunately, it still introduces an additional load on the database since the Token object must be queried (the accepted answer has this problem as well). The trick with SimpleLazyObject in this answer is a much better solution, but it didn't work for my use case because I need the user info in the middleware directly - I'm extending the metrics in django_prometheus and it processes the request before get_response is called.

from rest_framework.request import Request as RestFrameworkRequest
from rest_framework.views import APIView

class MyMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        drf_request: RestFrameworkRequest = APIView().initialize_request(request)
        user = drf_request.user
        ...
        return self.get_response(request)

I've solved this problem by getting DRF token from the requests and loading request.user to the user associated to that model.

I had the default django authentication and session middleware, but it seems DRF was using it's token auth after middleware to resolve the user (All requests were CORS requests, this might have been why). Here's my updated middleware class:

from re import sub
from rest_framework.authtoken.models import Token
from core.models import OrganizationRole, Organization, User

class OrganizationMiddleware(object):

  def process_view(self, request, view_func, view_args, view_kwargs):
    header_token = request.META.get('HTTP_AUTHORIZATION', None)
    if header_token is not None:
      try:
        token = sub('Token ', '', request.META.get('HTTP_AUTHORIZATION', None))
        token_obj = Token.objects.get(key = token)
        request.user = token_obj.user
      except Token.DoesNotExist:
        pass
    #This is now the correct user
    print (request.user)

This can be used on process_view or process_request as well.

Hopefully this can help someone out in the future.


Based on Daniel Dubovski's very elegant solution above, here's an example of middleware for Django 1.11:

from django.utils.functional import SimpleLazyObject
from organization.models import OrganizationMember
from django.core.exceptions import ObjectDoesNotExist


def get_active_member(request):
    try:
        active_member = OrganizationMember.objects.get(user=request.user)
    except (ObjectDoesNotExist, TypeError):
        active_member = None
    return active_member


class OrganizationMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response


    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        request.active_member = SimpleLazyObject(lambda: get_active_member(request))

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.
        return response

Came across this today while having the same problem.

TL;DR;

Skip below for code example


Explanation

Thing is DRF have their own flow of things, right in the middle of the django request life-cycle.

So if the normal middleware flow is :

  1. request_middleware (before starting to work on the request)
  2. view_middleware (before calling the view)
  3. template_middleware (before render)
  4. response_middleware (before final response)

DRF code, overrides the default django view code, and executes their own code.

In the above link, you can see that they wrap the original request with their own methods, where one of those methods is DRF authentication.

So back to your question, this is the reason using request.user in a middleware is premature, as it only gets it's value after view_middleware** executes.

The solution I went with, is having my middleware set a LazyObject. This helps, because my code (the actual DRF ApiVIew) executes when the actual user is already set by DRF's authentication. This solution was proposed here together with a discussion.

Might have been better if DRF had a better way to extend their functionality, but as things are, this seems better than the provided solution (both performance and readability wise).


Code Example

from django.utils.functional import SimpleLazyObject

def get_actual_value(request):
    if request.user is None:
        return None

    return request.user #here should have value, so any code using request.user will work


class MyCustomMiddleware(object):
    def process_request(self, request):
        request.custom_prop = SimpleLazyObject(lambda: get_actual_value(request))