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

发布于 2025-01-18 20:27:03 字数 3012 浏览 0 评论 0原文

我想限制登录的用户只有一个活动会话,即,如果用户使用新的SessionID登录,则应终止旧会话。 我已经找到了很多帮助: 在这里 and 和>在这里

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

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

,很好...

到目前为止 mod_wsgi),它行不通!

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

我发现的最接近的是 this ,但这是“相反的”问题……

任何帮助都将不胜感激。

编辑:在删除会话之前,我添加了调试打印... 片段。

[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

错误

这是apache 记录不会被删除... ???

我正在运行与与devServer的postgresql实例完全相同...

edit2:事实证明我的代码是故障...当新的session_key中未找到新的session_key ...

这是 失败的...固定代码...尝试..外面现在位于正确的位置

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦幻的味道 2025-01-25 20:27:03

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

当用户登录时,检查所有活动会话并删除具有相同 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)

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)
_蜘蛛 2025-01-25 20:27:03

您始终可以使用这种方法,尽管不建议使用这种方法。

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

在对用户进行身份验证之前,您将在登录()函数中实现上述代码。

当然,只有在您有一个登录()函数方法的情况下,该方法将用户在他的会话中存储用户,如下所示:

request.session["_username"] = request.user.username

如果您使用此方法,请记住在完成后运行服务器之前将所有会话的数据库清空这些更改是因为它会引起密钥lookup错误。

You can always use this approach though not recommended, it works.

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

You would implement the code above in your login() function right before authenticating the user.

This of course only works if you have a login() function method that stores the USERS username in his session like follows:

request.session["_username"] = request.user.username

If you use this approach just remember to empty your database of all of your sessions before running your server after you've made these changes because it will raise KeyLookUp errors.

早乙女 2025-01-25 20:27:03

我觉得,以某种方式,django.contrib.auth信号可以在这里提供帮助。登录时,使较旧的用户会话无效。

I feel that, somehow, django.contrib.auth signals could help here. On login, invalidate older user sessions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文