Search code examples
djangodjango-authenticationdjango-cache

Caching authenticated users in Redis?


Nearly all pages in my Django application require authentication. The app uses Django's AuthenticationMiddleware, so on every request the application hits the DB to retrieve the authenticated user.

I recently started storing session data in a Redis-backed cache. Since that has been working out great, eliminating one DB query per request by fetching session data from the cache, I'm wondering if I could also store authenticated users in Redis as well?

I am considering implementing this with a custom authentication backend, which would just subclass Django's ModelBackend, overriding the get_user() method:

# backends.py
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model

class MyAuthBackend(ModelBackend):

    def get_user(self, user_id):
        user = get_user_from_cache(user_id)  # not implemented here
        if user is None:
            UserModel = get_user_model()
            try:
                user = UserModel._default_manager.get(pk=user_id)
            except UserModel.DoesNotExist:
                return None
            else:
                set_user_in_cache(user)  # not implemented here
                return user

Hooking this up in settings:

# settings.py
AUTHENTICATION_BACKENDS = ('myapp.backends.MyAuthBackend',)

I should also probably note:

I probably don't intend to cache the entire user object. Instead, this will probably just cache a basic dictionary that contains only the user info that the application need on every page (like the user_id, name, etc). So the user attribute added to every incoming request object by Django's AuthenticationMiddleware will not be an instance of my user model.

Is this a good idea? Are there any downsides? And, if it's okay, is this the preferred way of accomplishing this?

Thanks a lot!

Update:

I've been caching user data successfully in Redis for a while now. However, instead of creating a custom authentication backend as I originally planned and described in the question, I completely replaced django's AuthenticationMiddleware instead.

The inspiration came from this package and my implementation is very similar.


Solution

  • Caching users is something very common, nothing wrong with that. I think a simpler and better approach than yours, is to use something like cache machine (https://cache-machine.readthedocs.org/en/latest/) which will also take care of invalidating the cache when necessary. As bonus point you also add something to your stack that you can you for caching other commonly queried models.