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

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

问题描述

我想限制登录用户只有一个活动会话,即如果用户使用新的sessionid登录,那么旧会话应该被终止。
我已经发现了很多关于SO的帮助:
这里这里



我实现了中间件解决方案,有一点额外的检查...

  class OnlyOneUserMiddleware(object):

确保登录用户只有一个会话处于活动状态的中间件$

def process_request(self,request):
如果request.user.is_authenticated():
try:
cur_session_key = request.user.get_profile()。session_key
如果cur_session_key和cur_session_key!= request.session.session_key:
#默认处理...踢旧会话...
Session.objects.get(session_key可以= cur_session_ key).delete()
如果不是cur_session_key或cur_session_key!= request.session.session_key:
p = request.user.get_profile()
p.session_key = request.session.session_key
p.save()
除了ObjectDoesNotExist:
pass

到目前为止,很好...在Django dev服务器(manage.py runserver)上,一切正常,它会启动旧会话...



...但是当使用Apache(与mod_wsgi),它不工作!



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



最近我找到的是这个 ,但它是一种相反的问题...



任何帮助将不胜感激。



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

  [Fri Jan 20 09:56:50 2012] [error] old key = f42885ccb7f33b6afcb2c18fca14f44a 
[Fri Jan 20 09:56:50 2012] [错误] 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)中输入



最后两个是从第二个会话(Chromium)输入的时候。



...事实证明,旧会话记录不会被删除... ...



我正在运行,而且与使用devserver的PostgreSQL实例完全相同...



编辑2:原来我的代码是错误的...当在Sessio中找不到新的Session_key时,它失败了n ...



这里是固定的代码... try..except现在在正确的地方

  class OnlyOneUserMiddleware(object):

确保登录用户只有一个会话处于活动状态的中间件。
将会弹出任何上一个会话。

def process_request(self,request):
如果request.user.is_authenticated():
cur_session_key = request.user.get_profile()。session_key
如果cur_session_key和cur_session_key!= request.session.session_key:
#默认处理...踢旧会话
try:
s = Session.objects.get(session_key = cur_session_key )
s.delete()
除了ObjectDoesNotExist:
pass
如果不是cur_session_key或cur_session_key!= request.session.session_key:
p = request.user.get_profile( )
p.session_key = request.session.session_key
p.save()


解决方案

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



当用户登录过去所有的交流请使用相同的 user.id 删除它们。对于较小的网站,这应该很好。

 #__init__.py 
#从所有其他会话中记录用户在登录时,django 1.8

从django.contrib.sessions.models导入会话
从django.contrib.auth.signals导入user_logged_in
从django.db.models导入Q
from django.utils import timezone

def limit_sessions(发件人,用户,请求,** kwargs):
#对于活跃用户的LOTS的网站,这将很慢

在Session.objects.filter中的会话(
〜Q(session_key = request.session.session_key),
expire_date__gte = timezone.now()
):
data = session.get_decoded()
如果data.get('_ auth_user_id',无)== str(user.id):
#找到重复的会话,过期它
session.expire_date = timezone.now()
session.save()

返回

user_logged_in.connect(limit_sessions)
/ pre>

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

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

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

Any help would be much appreciated.

Edit: 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

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

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

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

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

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

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.

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天全站免登陆