Search code examples
djangodjango-sessions

How to make a django user inactive and invalidate all their sessions


To make a user inactive I usually do:

User.objects.get(pk=X).update(is_active=False)

However, this doesn't log out the user or do anything session-related. Is there a built-in in django to make a user immediately inactive, or what would be the best way to accomplish this?

One similar answer is this: https://stackoverflow.com/a/954318/651174, but that doesn't work great if there are millions of sessions (it's a brute force way iterating over all sessions). Though this is from 2009, so hopefully there's a better way as of today.


Solution

  • As mentioned, you can use django-user-session or django-qsessions. But these include some other metadata such as user agent and ip address, and you may not want these for some reason. Then you need to write your custom session backend

    I adjusted the example a bit and created one to the my needs.

    session_backend.py:

    from django.contrib.auth import get_user_model
    from django.contrib.sessions.backends.db import SessionStore as DBStore
    from django.contrib.sessions.base_session import AbstractBaseSession
    from django.db import models
    
    User = get_user_model()
    
    
    class QuickSession(AbstractBaseSession):
        # Custom session model which stores user foreignkey to asssociate sessions with particular users.
        user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
    
        @classmethod
        def get_session_store_class(cls):
            return SessionStore
    
    
    class SessionStore(DBStore):
        @classmethod
        def get_model_class(cls):
            return QuickSession
    
        def create_model_instance(self, data):
            obj = super().create_model_instance(data)
    
            try:
                user_id = int(data.get('_auth_user_id'))
                user = User.objects.get(pk=user_id)
            except (ValueError, TypeError, User.DoesNotExist):
                user = None
            obj.user = user
            return obj
    

    and in settings.py:

    SESSION_ENGINE = 'path.to.session_backend'
    

    To delete all session for a user:

    from session_backend import QuickSession
    QuickSession.objects.filter(user=request.user).delete()
    

    You may write your custom save method for user model to automatically delete all sessions for the user if the is_active field is set to False.

    Keep in mind that, user field for those who are not logged in will be NULL.