【问题标题】:Django - Session managementDjango - 会话管理
【发布时间】:2020-02-12 17:27:02
【问题描述】:

我想防止同一个用户帐户在我的应用程序中有多个活动会话,并遵循this question 的回答。

我在我的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)


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)
    )

它工作得很好,但是,我注意到一个奇怪的行为。

如果我使用一个帐户登录,然后打开一个隐身窗口并使用相同的凭据登录,第一个帐户将被注销(这正是我想要的)。

但是,如果我使用帐户登录,然后关闭浏览器,下次我想登录时,我会在该行收到错误:

# save current session
request.session.save()

带有以下回溯(没有太多信息..):

UpdateError at /

未提供异常消息

控制台日志显示错误来自

django.contrib.sessions.backends.base.UpdateError

之后,如果我刷新页面,我就可以成功登录了。

对可能发生的事情有任何见解吗?

【问题讨论】:

    标签: python django python-3.x django-models


    【解决方案1】:

    您收到该错误是因为数据库中不再有要更新的会话,您已经删除了所有活动会话 2 行以上。要解决这个问题,只需在清理它们时忽略当前活动的会话:

    @receiver(user_logged_in)
    def remove_other_sessions(sender, user, request, **kwargs):
        # remove other sessions
        old_sessions = Session.objects.filter(usersession__user=user)
        if request.session.session_key:
            old_sessions = old_sessions.exclude(session_key=request.session.session_key)
        old_sessions.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)
        )
    

    【讨论】:

      【解决方案2】:

      @GwynBleidD 的回答很好!但这里有一个小错误:

      if request.session.session_key:
              old_sessions = old_sessions.exclude(session_key=request.session.session_key)

      应该写成:

      if request.session.session_key:
              old_sessions = old_sessions.exclude(session_key=request.session.session_key).delete()
      else:
          old_sessions.delete()
      否则当您第二次尝试在同一台计算机上登录时会出现错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-03
        • 1970-01-01
        • 1970-01-01
        • 2012-10-11
        • 2011-04-29
        • 2011-10-22
        • 2011-08-01
        • 2012-11-12
        相关资源
        最近更新 更多