Django allow only one user session in total

蹲街弑〆低调 提交于 2019-12-11 14:23:32

问题


I currently try to implement a policy to my application that only one user session at a time is allowed, if a user trys to log-in from another device the old sessions gets killed.

But for some resone i get the following error and i can't find the mistake myself :( :

RelatedObjectDoesNotExist at / User has no logged_in_user.

My project contains two apps, the actually app and a "accounts" app that contains all informations shown here.

signals.py

# Signals that fires when a user logs in and logs out

from django.contrib.auth import user_logged_in, user_logged_out
from django.dispatch import receiver
from .models import LoggedInUser

@receiver(user_logged_in)
def on_user_logged_in(sender, request, **kwargs):
    LoggedInUser.objects.get_or_create(user=kwargs.get('user'))


@receiver(user_logged_out)
def on_user_logged_out(sender, **kwargs):
    LoggedInUser.objects.filter(user=kwargs.get('user')).delete()

models.py

# Model to store the list of logged in users
class LoggedInUser(models.Model):
    user = models.OneToOneField(User, related_name='logged_in_user', on_delete=models.CASCADE)
    session_key = models.CharField(max_length=32, null=True, blank=True)

    def __str__(self):
        return self.user

my User Model is at the same at the same location as this sippet

middleware.py

#Session model stores the session data
from django.contrib.sessions.models import Session
from .models import LoggedInUser

class OneSessionPerUserMiddleware:
    # Called only once when the web server starts
    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.
        if request.user.is_authenticated:
            stored_session_key = request.user.logged_in_user.session_key

            # if there is a stored_session_key in the database and it is
            # different from the current session, delete the stored_session_key
            # session_key with from the Session table
            if stored_session_key and stored_session_key != request.session.session_key:
                Session.objects.get(session_key=stored_session_key).delete()

            request.user.logged_in_user.session_key = request.session.session_key
            request.user.logged_in_user.save()

        response = self.get_response(request)

        # This is where you add any extra code to be executed for each request/response after
        # the view is called.

        return response

UPDATE:

my middleware.py file now looks like:

# Session model stores the session data
from django.contrib.sessions.models import Session
from .models import LoggedInUser


class OneSessionPerUserMiddleware:
    # Called only once when the web server starts
    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.
        if request.user.is_authenticated:
            session_key = request.session.session_key

            # if there is a stored_session_key  in our database and it is
            # different from the current session, delete the stored_session_key
            # session_key with from the Session table
            try:
                logged_in_user = request.user.logged_in_user
                stored_session_key = logged_in_user.session_key
                # stored_session_key exists so delete it if it's different
                if stored_session_key != session_key:
                    Session.objects.filter(session_key=stored_session_key).delete()
                logged_in_user.session_key = session_key
                logged_in_user.save()
            except LoggedInUser.DoesNotExist:
                LoggedInUser.objects.create(user=request.user, session_key=session_key)

        response = self.get_response(request)

        return response

which seems to work fine but if i log in with the same user from two different browsers, I'm still able to do this and i still get two different sessions keys and the session stays open.

If i check at the database while logged in from two diffrent computers to access the application as the same user, the saved session key at the LoggedInUser table simple changes but the application does not act like the key has been revoked from at least the oldest session!?


回答1:


Actually the error occurs here,

stored_session_key = request.user.logged_in_user.session_key

ie. the related logged_in_user (LoggedInUser object) doesn't exists for the logged in user. So you have to create a a new one.

session_key = request.session.session_key

try:
    logged_in_user = request.user.logged_in_user
    stored_session_key = logged_in_user.session_key
    # stored_session_key exists so delete it if it's different
    if stored_session_key != session_key:
        Session.objects.filter(session_key=stored_session_key).delete()
    logged_in_user.session_key = session_key
    logged_in_user.save()
except LoggedInUser.DoesNotExist:
    LoggedInUser.objects.create(user=request.user, session_key=session_key)



回答2:


This one works and answers your question.:

class OneSessionPerUserMiddleware:
# Called only once when the web server starts
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.
    if request.user.is_authenticated:
        session_key = request.session.session_key

        try:
            logged_in_user = request.user.logged_in_user
            stored_session_key = logged_in_user.session_key
            # stored_session_key exists so delete it if it's different
            if stored_session_key and stored_session_key != request.session.session_key:
                Session.objects.get(session_key=stored_session_key).delete()
            request.user.logged_in_user.session_key = request.session.session_key
            request.user.logged_in_user.save()
        except LoggedInUser.DoesNotExist:
            LoggedInUser.objects.create(user=request.user, session_key=session_key)
        stored_session_key = request.user.logged_in_user.session_key

        # if there is a stored_session_key  in our database and it is
        # different from the current session, delete the stored_session_key
        # session_key with from the Session table
        if stored_session_key and stored_session_key != request.session.session_key:
            Session.objects.get(session_key=stored_session_key).delete()

        request.user.logged_in_user.session_key = request.session.session_key
        request.user.logged_in_user.save()

    response = self.get_response(request)

    # This is where you add any extra code to be executed for each request/response after
    # the view is called.
    # For this tutorial, we're not adding any code so we just return the response

    return response


来源:https://stackoverflow.com/questions/56312743/django-allow-only-one-user-session-in-total

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!