Как мне определить, когда у пользователя есть тайм-аут ожидания в Django?

StackOverflow https://stackoverflow.com/questions/644471

  •  22-07-2019
  •  | 
  •  

Вопрос

Я хотел бы провести аудит, когда пользователь испытал тайм-аут простоя в моем приложении Django.Другими словами, если срок действия сессионного файла cookie пользователя превышает значение SESSION_COOKIE_AGE, указанное в settings.py, пользователь перенаправляется на страницу входа в систему.Когда это происходит, также должен быть проведен аудит.Под "аудитом" я подразумеваю, что запись должна быть записана в таблицу my person.audit.

В настоящее время я настроил некоторое промежуточное программное обеспечение для захвата этих событий.К сожалению, Django генерирует новый файл cookie, когда пользователь перенаправляется на страницу входа в систему, поэтому я не могу определить, был ли пользователь переведен на страницу входа через тайм-аут ожидания или какое-либо другое событие.

Из того, что я могу сказать, мне нужно было бы поработать с таблицей "django_session".Однако записи в этой таблице не могут быть связаны с этим пользователем, поскольку значение sessionid в файле cookie сбрасывается при перенаправлении.

Полагаю, я не первый, кто сталкивается с этой дилеммой.Есть ли у кого-нибудь представление о том, как решить эту проблему?

Это было полезно?

Решение

Обновить:

После небольшого тестирования я понимаю, что приведенный ниже код не отвечает на ваш вопрос.Хотя это работает, и вызывается обработчик сигнала, prev_session_data если он и существует, то не будет содержать никакой полезной информации.

Во-первых, взглянем изнутри на структуру сессий:

  1. Когда новый посетитель запрашивает URL-адрес приложения, для него генерируется новый сеанс - на этом этапе он по-прежнему анонимен (request.user является экземпляром AnonymousUser).
  2. Если они запрашивают представление, требующее проверки подлинности, они перенаправляются на представление входа в систему.
  3. Когда запрашивается представление входа в систему, оно устанавливает тестовое значение в сеансе пользователя (SessionStore._session);это автоматически устанавливает accessed и modified флаги для текущего сеанса.
  4. На этапе ответа на вышеуказанный запрос SessionMiddleware сохраняет текущий сеанс, эффективно создавая новый Session экземпляр в django_session таблица (если вы используете сеансы, поддерживаемые базой данных по умолчанию, предоставляемые django.contrib.sessions.backends.db).Идентификатор нового сеанса сохраняется в settings.SESSION_COOKIE_NAME печенье.
  5. Когда пользователь вводит свое имя пользователя и пароль и отправляет форму, он проходит проверку подлинности.Если аутентификация пройдет успешно, то login способ из django.contrib.auth называется. login проверяет, содержит ли текущий сеанс идентификатор пользователя;если это так, и идентификатор совпадает с идентификатором вошедшего в систему пользователя, SessionStore.cycle_key вызывается для создания нового ключа сеанса с сохранением данных сеанса.В противном случае, SessionStore.flush вызывается, чтобы удалить все данные и сгенерировать новый сеанс.Оба этих метода должны удалить предыдущий сеанс (для анонимного пользователя) и вызвать SessionStore.create чтобы создать новый сеанс.
  6. На этом этапе пользователь проходит проверку подлинности, и у него начинается новый сеанс.Их идентификатор сохраняется в сеансе вместе с серверной частью, используемой для их аутентификации.Промежуточное программное обеспечение сеанса сохраняет эти данные в базе данных и сохраняет их новый идентификатор сеанса в settings.SESSION_COOKIE_NAME.

Итак, вы видите, что большая проблема с предыдущим решением заключается в том, что ко времени create вызывается (шаг 5.), идентификатор предыдущего сеанса давно исчез.Как другие указывали на это, это происходит потому, что по истечении срока действия сессионного файла cookie браузер автоматически удаляет его.

Опираясь на Предложение Алекса Гейнора, Я думаю, что я придумал другой подход, который, кажется, делает то, о чем вы просите, хотя он все еще немного грубоват по краям.По сути, я использую второй долговременный файл cookie "аудита" для зеркального отображения идентификатора сеанса и некоторое промежуточное программное обеспечение для проверки наличия этого файла cookie.По любому запросу:

  • если ни файл cookie аудита, ни файл cookie сеанса не существуют, вероятно, это новый пользователь
  • если файл cookie аудита существует, но файл cookie сеанса отсутствует, вероятно, это пользователь, чей сеанс только что истек
  • если оба файла cookie существуют и имеют одинаковое значение, это активный сеанс

Пока что вот код:

sessionaudit.middleware.py:

from django.conf import settings
from django.db.models import signals
from django.utils.http import cookie_date
import time

session_expired = signals.Signal(providing_args=['previous_session_key'])

AUDIT_COOKIE_NAME = 'sessionaudit'

class SessionAuditMiddleware(object):
    def process_request(self, request):
        # The 'print' statements are helpful if you're using the development server
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
        audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
        if audit_cookie is None and session_key is None:
            print "** Got new user **"
        elif audit_cookie and session_key is None:
            print "** User session expired, Session ID: %s **" % audit_cookie
            session_expired.send(self.__class__, previous_session_key=audit_cookie)
        elif audit_cookie == session_key:
            print "** User session active, Session ID: %s **" % audit_cookie

    def process_response(self, request, response):
        if request.session.session_key:
            audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
            if audit_cookie != request.session.session_key:
                # New Session ID - update audit cookie:
                max_age = 60 * 60 * 24 * 365  # 1 year
                expires_time = time.time() + max_age
                expires = cookie_date(expires_time)
                response.set_cookie(
                    AUDIT_COOKIE_NAME,
                    request.session.session_key,
                    max_age=max_age,
                    expires=expires,
                    domain=settings.SESSION_COOKIE_DOMAIN,
                    path=settings.SESSION_COOKIE_PATH,
                    secure=settings.SESSION_COOKIE_SECURE or None
                )
        return response

audit.models.py:

from django.contrib.sessions.models import Session
from sessionaudit.middleware import session_expired

def audit_session_expire(sender, **kwargs):
    try:
        prev_session = Session.objects.get(session_key=kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data.get('_auth_user_id')
    except Session.DoesNotExist:
        pass

session_expired.connect(audit_session_expire)

settings.py:

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'sessionaudit.middleware.SessionAuditMiddleware',
    ...
)

INSTALLED_APPS = (
    ...
    'django.contrib.sessions',
    'audit',
    ...
)

Если вы используете это, вам следует реализовать пользовательское представление выхода из системы, которое явно удаляет файл cookie аудита при выходе пользователя из системы.Кроме того, я бы предложил использовать промежуточное программное обеспечение django signed-cookies (но вы, вероятно, уже делаете это, не так ли?)

Старый:

Я думаю, вы должны быть в состоянии сделать это, используя пользовательский сервер сеанса.Вот несколько (непроверенных) примеров кода:

from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.db.models import signals

session_created = signals.Signal(providing_args=['previous_session_key', 'new_session_key'])

class SessionStore(DBStore):
    """
    Override the default database session store.

    The `create` method is called by the framework to:
    * Create a new session, if we have a new user
    * Generate a new session, if the current user's session has expired

    What we want to do is override this method, so we can send a signal
    whenever it is called.
    """

    def create(self):
        # Save the current session ID:
        prev_session_id = self.session_key
        # Call the superclass 'create' to create a new session:
        super(SessionStore, self).create()
        # We should have a new session - raise 'session_created' signal:
        session_created.send(self.__class__, previous_session_key=prev_session_id, new_session_key=self.session_key)

Сохраните приведенный выше код как 'customdb.py' и добавьте его в свой проект django.В вашем settings.py установите или замените 'SESSION_ENGINE' путем к указанному выше файлу, например:

SESSION_ENGINE = 'yourproject.customdb'

Тогда в вашем промежуточное программное обеспечение, или models.py , предоставьте обработчик для сигнала 'session_created', например:

from django.contrib.sessions.models import Session
from yourproject.customdb import session_created

def audit_session_expire(sender, **kwargs):
    # remember that 'previous_session_key' can be None if we have a new user
    try:
        prev_session = Session.objects.get(kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data['_auth_user_id']
        # do something with the user_id
    except Session.DoesNotExist:
        # new user; do something else...

session_created.connect(audit_session_expire)

Не забудьте включить приложение, содержащее models.py в INSTALLED_APPS.

Другие советы

SESSION_COOKIE_AGE = 1500 # 25 минут

Установите это в своих настройках, и это должно позаботиться об этом и завершить сеанс.

Я не знаю о Django, но можете ли вы просто создать непостоянный файл cookie, в котором хранится время последнего доступа к странице на вашем сайте (файл cookie обновляется при каждой загрузке страницы)

Затем на странице входа в систему вы можете проверить, есть ли у вашего пользователя ваш файл cookie, но нет сеанса, тогда вы знаете, что время сеанса пользователя, вероятно, истекло. Поскольку у вас есть время последнего доступа к странице на вашем сайте, вы также можете рассчитать, исходя из продолжительности сеанса, если он истек.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top