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

查看:98
本文介绍了如何防止在 Django 中多次登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个无法同时登录的用户系统.如果该帐户在某处处于登录状态,而有人在其他位置登录同一帐户.后一个将被登录.而前一个将被注销.我正在使用一个与用户模型关联的 oneToOneField 模型,并保存该用户的会话 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 附加到 Profile.在这种情况下,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?

推荐答案

我觉得你把事情搞得很复杂,把数据存到 UserProfiles 等等然后有信号,你介绍很多级别,在每个级别,事情都可能出错.

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 对象在 UserSession 之间建立了一个链接.现在我们可以实现一个登录钩子:一个在用户登录时触发的信号.在这种情况下,我们执行两件事:

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. 我们删除所有处于活动状态的UserSession(以及相应的UserSession);和
  2. 我们创建了一个新的 Session 和相应的 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_id=request.session.session_key
    )

这篇关于如何防止在 Django 中多次登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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