如何防止Django中的多次登录 [英] How to prevent multiple login in Django

查看:295
本文介绍了如何防止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 UserProfiles, 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 Users 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 会话 s。现在我们可以实现一个 login hook :一个在用户登录时触发的信号。在这种情况下,我们执行两件事:

So the UserSession object makes a link between User and Sessions. 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:


  1. 我们删除<$ c $的所有 Session s(和相应的 UserSession s) c>用户处于活动状态;并且

  2. 我们创建一个新的会话以及相应的 UserSession 后来。像这样:

  1. we delete all Sessions (and corresponding UserSessions) of the User that are active; and
  2. we create a new Session and corresponding UserSession 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆