在Django应用中,每个用户只允许一个活动会话

2024-10-01 13:44:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我想限制登录用户只有一个活动会话,即如果用户使用新的sessionid登录,则旧会话应该终止。 我已经找到了很多帮助: herehere

我实现了中间件解决方案,进行了一些额外的检查。。。在

class OnlyOneUserMiddleware(object):
"""
Middleware to ensure that a logged-in user only has one session active.
Will kick out any previous session. 
"""
def process_request(self, request):
    if request.user.is_authenticated():
        try:
            cur_session_key = request.user.get_profile().session_key
            if cur_session_key and cur_session_key != request.session.session_key:
                # Default handling... kick the old session...
                Session.objects.get(session_key=cur_session_key).delete()
            if not cur_session_key or cur_session_key != request.session.session_key:
                p = request.user.get_profile()
                p.session_key = request.session.session_key
                p.save()
        except ObjectDoesNotExist:
            pass

到目前为止,很好。。。在Django dev服务器上(管理运行服务器)一切正常,它踢旧的会话。。。在

…但是当使用Apache(与mod wsgi一起使用)时,它不起作用!在

我试着找到关于这件事的任何信息,但到目前为止还没有找到任何运气。。。在

我发现的最接近的是this,但这是一个“相反”的问题。。。在

任何帮助都将不胜感激。在

编辑:我在删除会话之前添加了调试打印。。。 这里有一段来自Apache的片段错误.log公司名称:

^{pr2}$

前两个谎言是我第一次进入的时候(Firefox)

最后两个是我进入第二个疗程时(铬)

。。。原来原来的会话记录没有被删除???在

我运行的是与devserver完全相同的PostgreSQL实例。。。在

编辑2:原来我的代码有缺陷。。。在会话中找不到新会话密钥时失败。。。在

这是固定密码。。。尝试…除了现在在正确的地方

class OnlyOneUserMiddleware(object):
    """
    Middleware to ensure that a logged-in user only has one session active.
    Will kick out any previous session. 
    """
    def process_request(self, request):
        if request.user.is_authenticated():
            cur_session_key = request.user.get_profile().session_key
            if cur_session_key and cur_session_key != request.session.session_key:
                # Default handling... kick the old session...
                try:
                    s = Session.objects.get(session_key=cur_session_key)
                    s.delete()
                except ObjectDoesNotExist:
                    pass
            if not cur_session_key or cur_session_key != request.session.session_key:
                p = request.user.get_profile()
                p.session_key = request.session.session_key
                p.save()

Tags: key用户getifhereobjectrequestsession
3条回答

确实到处都有类似的问题,但这里是我的解决办法。在

当用户登录到所有活动会话并删除具有相同user.id的会话时。对于较小的网站,这应该可以。在

# __init__.py
# Logs user out from all other sessions on login, django 1.8

from django.contrib.sessions.models import Session
from django.contrib.auth.signals import user_logged_in
from django.db.models import Q
from django.utils import timezone

def limit_sessions(sender, user, request, **kwargs):
    # this will be slow for sites with LOTS of active users

    for session in Session.objects.filter(
        ~Q(session_key = request.session.session_key),
        expire_date__gte = timezone.now()
    ):
        data = session.get_decoded()
        if data.get('_auth_user_id', None) == str(user.id):
            # found duplicate session, expire it
            session.expire_date = timezone.now()
            session.save()

    return

user_logged_in.connect(limit_sessions)

你可以一直使用这种方法,虽然不推荐,但它是有效的。在

my_old_sessions = Session.objects.all()
for row in my_old_sessions:
   if row.get_decoded().get("_username") == request.user.username:
      row.delete()

在对用户进行身份验证之前,可以在login()函数中实现上面的代码。在

当然,只有当您有一个login()函数方法将用户用户名存储在会话中时,此方法才有效,如下所示:

^{pr2}$

如果使用这种方法,只需记住在进行这些更改之后,在运行服务器之前清空数据库中的所有会话,因为这样会引发KeyLookUp错误。在

我觉得,不知怎么的,django.contrib.auth公司信号可能会有所帮助。登录时,使旧用户会话无效。在

相关问题 更多 >