在 Django 应用程序中,每个用户只允许一个活动会话 [英] Allowing only single active session per user in Django app

查看:24
本文介绍了在 Django 应用程序中,每个用户只允许一个活动会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想限制登录用户只能有一个活动会话,即如果用户使用新的 sessionid 登录,旧的会话应该终止.我已经在 SO 上找到了很多帮助:这里这里

I want to restrict logged-in users to only have one active session, i.e. if the user logs in with a new sessionid, the old session should be terminated. I found a lot of help on SO already: here and here

我实施了中间件解决方案,并进行了一些额外的检查...

I implemented the middleware solution, with a bit of extra checking...

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 开发服务器 (manage.py runserver) 上一切正常,它启动了旧会话...

So far, so good... on the Django dev server (manage.py runserver) everything works properly, it kicks the old session...

...但是当使用 Apache(带有 mod_wsgi)时,它不起作用!

...but when using Apache ( with mod_wsgi), it doesn't work!

我试图找到有关此的任何信息,但到目前为止没有运气...

I've tried to find any information about this, but no luck so far...

我发现的最接近的是这个,但它有点像'对面的问题...

The closest I have found is this, but it is kind of the 'opposite' problem...

任何帮助将不胜感激.

我在删除会话之前添加了调试打印...这是 Apache 的 error.log 中的一个片段:

I added a debug print before deleting the Session... here's a snippet from Apache's error.log:

[Fri Jan 20 09:56:50 2012] [error] old key = f42885ccb7f33b6afcb2c18fca14f44a
[Fri Jan 20 09:56:50 2012] [error] new key = ce4cfb672e6025edb8ffcd0cf2b4b8d1
[Fri Jan 20 09:57:14 2012] [error] old key = f42885ccb7f33b6afcb2c18fca14f44a
[Fri Jan 20 09:57:14 2012] [error] new key = 0815c56241ac21cf4b14b326f0aa7e24

前两个谎言来自我第一次进入时(Firefox)

the first two lies are from when I entered with the first session (Firefox)

最后两个是我进入第二个会话时的(Chromium)

the last two are from when I entered with the second session (Chromium)

...原来旧的Session记录没有被删除...???

... it turns out that the old Session record does not get deleted... ???

我正在运行与开发服务器完全相同的 PostgreSQL 实例...

I'm running vs. the exact same PostgreSQL instance as I did with the devserver...

Edit2:结果是我的代码有问题……当在 Session 中找不到新的 Session_key 时它失败了……

It turned out that my code was buggy... it failed when the new Session_key wasn't found in Session...

这是固定代码... try..except 现在在正确的位置

here's the fixed code... the try..except is now in the correct place

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

推荐答案

确实有很多类似的问题到处都是,但这里是我的解决方案.

There is indeed a lot of similar questions all over the place, but here is my solution.

当用户登录时,检查所有活动会话并删除具有相同 user.id 的会话.对于较小的网站,这应该没问题.

When a user logins go over all active sessions and remove the ones with the same user.id. For smaller websites, this should do just fine.

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

这篇关于在 Django 应用程序中,每个用户只允许一个活动会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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