在Django应用程序中,每个用户只允许单个活动会话 [英] Allowing only single active session per user in Django app
问题描述
我想限制登录用户只有一个活动会话,即如果用户使用新的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
/ pre>
#从所有其他会话中记录用户在登录时,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)
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屋!