问题
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