Разрешить только один активный сеанс для пользователя в приложении Django - PullRequest
22 голосов
/ 19 января 2012

Я хочу ограничить вошедших в систему пользователей только одним активным сеансом, т. Е. Если пользователь входит в систему с новым идентификатором сеанса, старый сеанс должен быть прерван.Я уже нашел много помощи по SO: здесь и здесь

Я реализовал решение промежуточного программного обеспечения с небольшой дополнительной проверкой ...

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) все работает нормально, запускает старый сеанс ...

... но при использовании Apache (с mod_wsgi), это не работает!

Я пытался найти какую-либо информацию об этом, но пока не повезло ...

Ближайшее, что я нашел, это это , но это своего рода «противоположная» проблема ...

Любая помощь будет принята с благодарностью.

Редактировать: я добавил отладочную печать перед удалением сеанса ... вот фрагмент из Apache 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)

последние два относятся к моменту, когда я вступил во второй сеанс (Chromium)

... получается, что старая запись сеанса не удаляется ...???

Я работаю против того же самого экземпляра PostgreSQL, который я делал с devserver ...

Edit2: Оказалось, что мой код глючил ...новый Session_key не был найден в Session ...

вот фиксированный код ... try..except теперь находится в правильном месте

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

Ответы [ 3 ]

1 голос
/ 07 мая 2015

Существует действительно много подобных вопросов повсюду, но вот мое решение.

Когда пользователь входит в систему, проходят все активные сеансы и удаляют те, которые имеют тот же 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)
1 голос
/ 26 января 2012

Вы всегда можете использовать этот подход, хотя и не рекомендуется, он работает.

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 (), который сохраняет имя пользователя USERS в своем сеансе следующим образом:

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

Если вы используете этот подход, просто не забудьте очистить базу данных всех сеансов перед запуском сервера после внесения этих изменений, поскольку это вызовет ошибки KeyLookUp.

0 голосов
/ 31 августа 2016

Мне кажется, что каким-то образом здесь могут помочь сигналы django.contrib.auth. При входе в систему, сделать недействительными старые пользовательские сессии.

...