如何防止Django中的多次登录 [英] How to prevent multiple login in Django
问题描述
我正在编写一个不能同时登录的用户系统。
如果处于登录状态的帐户在某处,并且有人在另一个位置登录了同一帐户。后者将被登录。而前一个将被注销。
我正在使用一个与oneToOneField关联到User模型的模型,并保存该用户的会话ID。
代码如下所示。
I'm writing a User system that cannot login at the same time. If the account in login state in somewhere, and someone login the same account in other position. The latter one will be logged in. And the previous will be logged out. I'm using a model with oneToOneField associated to the User model, And save session ids of this user. The code is like below.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from .myModels import JSONField
class Profile(models.Model):
user = models.OneToOneField(User, models.CASCADE)
sessionids = JSONField(null=True)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
JSONField是一个使用textField存储JSON字符串的字段。
当用户登录时,我去获取该用户的所有会话ID并删除所有会话ID。然后,我将当前会话ID添加到配置文件中。这样,我可以登出上一个职位。代码如下所示。
The JSONField is a field that using textField to store JSON string. When a user login, I go to get all session ids of this user and delete all the session ids. Then I add current session id to the Profile. By doing this, I can logout in the previous position. the code is like below.
def login(request):
if request.method == "POST":
if request.user.is_authenticated:
return HttpResponse("the user session is authenticated.")
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
auth.login(request, user)
#remove cur user all sessions
sessionidsToDelete = request.user.profile.sessionids
if sessionidsToDelete != None:
sessions = Session.objects.filter(session_key__in=sessionidsToDelete)
for session in sessions:
session.delete()
#add cur user sessions
sessionidsToStore = user.profile.sessionids
print("sessionidsToStore = ")
print(sessionidsToStore)
print("sessionidsToDelete = ")
print(sessionidsToDelete)
if sessionidsToStore== None:
sessionidsToStore = []
else:
sessionidsToStore = list(set(sessionidsToStore) - set(sessionidsToDelete))
print("sessionidsToStore = ")
print(sessionidsToStore)
sessionidsToStore.append(request.session.session_key)
user.profile.sessionids = json.dumps(sessionidsToStore)
user.profile.save()
rotate_token(request)
return HttpResponse("login sucessful")
elif user.is_active == False:
userNotActivedHttpresponse = HttpResponse()
userNotActivedHttpresponse.status_code = 605
userNotActivedHttpresponse.reason_phrase = "This user not active"
return userNotActivedHttpresponse
else:
return HttpResponse("Please Input the correct username and password")
else:
return HttpResponseBadRequest("Please use POST to login")
但我认为会发生一些事情。当有两个人要同时登录同一帐户时。
例如,有两个人知道同一个帐户。
他们同时登录。在A删除所有其他会话ID之后,B可能会将B的会话ID附加到个人资料中。在这种情况下,A和B仍将处于登录状态,并且不会注销。我该如何预防该问题?
But I think something will happen. When there two people want to login the same account at the same time. For example, there are two people know the same account. They login at the same time. It may be happen that B append B's session id to Profile after A remove all other session ids. In this situation, A and B will still in login state, and won't be logout. How could I prevent this problem?
推荐答案
我认为您将数据存储在中使事情变得非常复杂。 UserProfile
s等,然后发出信号,您介绍了很多级别,每个级别都有可能出错。
I think you make things very complicated, by storing data in UserProfile
s, etc. and then have signals, you introduce a lot of levels, and at each level, things can go wrong.
我们基本上,这里需要两件事:将 User
映射到其相应设置的表。我们可以使用 UserSession
模型来实现:
We basically need two things here: a table that maps User
s to their corresponding settings. We can implement this with a UserSession
model:
# models.py
from django.conf import settings
from django.db import models
from django.contrib.sessions.models import Session
class UserSession(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
session = models.OneToOneField(Session, on_delete=models.CASCADE)
因此 UserSession
对象在 User $ c $之间建立了链接c>和
会话
s。现在我们可以实现一个 login hook :一个在用户登录时触发的信号。在这种情况下,我们执行两件事:
So the UserSession
object makes a link between User
and Session
s. Now we can implement a login hook: a signal that is triggered in case a user logs in. In that case we perform two things:
- 我们删除<$ c $的所有
Session
s(和相应的UserSession
s) c>用户处于活动状态;并且 - 我们创建一个新的
会话
以及相应的UserSession
后来。像这样:
- we delete all
Session
s (and correspondingUserSession
s) of theUser
that are active; and - we create a new
Session
and correspondingUserSession
that we can remove later. Like:
from django.contrib.auth import user_logged_in
from django.dispatch.dispatcher import receiver
@receiver(user_logged_in)
def remove_other_sessions(sender, user, request, **kwargs):
# remove other sessions
Session.objects.filter(usersession__user=user).delete()
# save current session
request.session.save()
# create a link from the user to the current session (for later removal)
UserSession.objects.get_or_create(
user=user,
session=Session.objects.get(pk=request.session.session_key)
)
这篇关于如何防止Django中的多次登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!