django - 如何防止在Django中多次登录
问题描述
我正在编写一个无法同时登录的用户系统。如果帐户在某处处于登录状态,而有人在其他位置登录同一帐户。后一个将被登录。前一个将被注销。我正在使用与用户模型关联的 oneToOneField 模型,并保存该用户的会话 ID。代码如下所示。
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 添加到配置文件中。通过这样做,我可以在以前的位置注销。代码如下。
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 附加到 Profile 中。在这种情况下,A 和 B 仍然处于登录状态,不会退出。我怎样才能防止这个问题?
解决方案
我觉得你把事情搞的很复杂,把数据存到UserProfile
s里面等等然后有信号,你引入了很多层级,而在每个层级,事情都可能出错。
我们在这里基本上需要两件事:一个将User
s 映射到其相应设置的表。我们可以用一个UserSession
模型来实现它:
# 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)
所以对象在和sUserSession
之间建立了联系。现在我们可以实现一个登录钩子:一个在用户登录时触发的信号。在这种情况下,我们执行两件事:User
Session
- 我们删除所有活跃的
Session
s(和相应UserSession
的 s) ;User
和 - 我们创建一个新的
Session
和对应UserSession
的,我们可以稍后删除。喜欢:
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_id=request.session.session_key
)
推荐阅读
- node.js - nodejs i18n __ 不是 ejs 的功能问题,表达
- python - 烧瓶重定向后,我的数据无效
- javascript - Angular 中的后台数据加载和解析器
- javascript - CSS - 改变盒子大小和链接背景图片
- java - 我可以在java中实现一个带有变量的类吗?
- oracle11g - 如何删除 - 从右到左读取字符串值时
- swift - 为什么 URLSession 不在 URLSessionDownloadDelegate 中?
- django - 如何将查询参数传递给 django rest api javascript 客户端
- c# - 从日期时间中减去未知间隔
- java - 迭代数组并打印不同的字符串输出