Подтвердить что ты не робот

Как истечь сеанс из-за бездействия в Django?

В нашем приложении Django есть следующие требования к управлению сеансом.

  • Сессии истекают, когда пользователь закрывает браузер.
  • Сессии истекают после периода бездействия.
  • Обнаружение, когда сеанс истекает из-за неактивности и отображает соответствующее сообщение пользователю.
  • Предупреждать пользователей о предстоящем завершении сеанса за несколько минут до окончания периода бездействия. Наряду с предупреждением, предоставить пользователям возможность продлить сеанс.
  • Если пользователь работает с длинной деловой активностью в приложении, которая не включает запросы, отправляемые на сервер, сеанс не должен истекать.

После прочтения документации, кода Django и некоторых сообщений в блоге, связанных с этим, я придумал следующий подход к реализации.

Требование 1
Это требование легко реализовать, установив для параметра SESSION_EXPIRE_AT_BROWSER_CLOSE значение True.

Требование 2
Я видел несколько рекомендаций по использованию SESSION_COOKIE_AGE для установки периода истечения срока действия сеанса. Но этот метод имеет следующие проблемы.

  • Сессия всегда заканчивается в конце SESSION_COOKIE_AGE, даже если пользователь активно использует приложение. (Этого можно предотвратить, установив время окончания сеанса на SESSION_COOKIE_AGE для каждого запроса с использованием специального промежуточного программного обеспечения или путем сохранения сеанса для каждого запроса, установив для параметра SESSION_SAVE_EVERY_REQUEST значение true. Но следующая проблема неизбежна из-за использования SESSION_COOKIE_AGE.)

  • Из-за того, как файлы cookie работают, SESSION_EXPIRE_AT_BROWSER_CLOSE и SESSION_COOKIE_AGE являются взаимоисключающими, т.е. файл cookie либо истекает, либо закрывается браузером или в указанное время истечения срока действия. Если используется SESSION_COOKIE_AGE, и пользователь закрывает браузер до истечения срока действия файла cookie, файл cookie сохраняется и повторное открытие браузера позволяет пользователю (или кому-либо еще) войти в систему без повторной аутентификации.

  • Django полагается только на присутствующий файл cookie, чтобы определить, активен ли сеанс. Он не проверяет дату окончания сеанса, хранящуюся в сеансе.

Для реализации этого требования и использования описанных выше проблем можно использовать следующий метод.

  • Не устанавливайте SESSION_COOKIE_AGE.
  • Установите дату истечения срока действия сеанса как "текущее время + период бездействия" для каждого запроса.
  • Переопределите process_request в SessionMiddleware и проверьте срок действия сеанса. Отмените сеанс, если он истек.

Требование 3
Когда мы обнаруживаем, что сеанс истек (в пользовательском SessionMiddleware выше), установите атрибут в запросе, чтобы указать истечение сеанса. Этот атрибут может использоваться для отображения соответствующего сообщения пользователю.

Требование 4
Используйте JavaScript, чтобы обнаружить неактивность пользователя, предоставьте предупреждение, а также возможность продлить сеанс. Если пользователь хочет продлить действие, отправьте на сервер продолж. Импульс, чтобы продлить сеанс.

Требование 5
Используйте JavaScript для определения активности пользователя (во время длительной бизнес-операции) и отправки оставшихся импульсов на сервер, чтобы не допустить завершения сеанса.


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

Любые идеи будут высоко оценены.

4b9b3361

Ответ 1

Вот идея... Завершите сеанс в браузере рядом с настройкой SESSION_EXPIRE_AT_BROWSER_CLOSE. Затем установите временную метку в сеансе для каждого запроса, например:

request.session['last_activity'] = datetime.now()

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

from datetime import datetime
from django.http import HttpResponseRedirect

class SessionExpiredMiddleware:
    def process_request(request):
        last_activity = request.session['last_activity']
        now = datetime.now()

        if (now - last_activity).minutes > 10:
            # Do logout / expire session
            # and then...
            return HttpResponseRedirect("LOGIN_PAGE_URL")

        if not request.is_ajax():
            # don't set this for ajax requests or else your
            # expired session checks will keep the session from
            # expiring :)
            request.session['last_activity'] = now

Затем вам просто нужно сделать некоторые URL-адреса и представления, чтобы вернуть соответствующие данные в вызовы ajax в отношении истечения срока действия сеанса.

когда пользователь выбирает "возобновить" сеанс, так сказать, все, что вам нужно сделать, это установить requeset.session['last_activity'] на текущее время снова

Очевидно, что этот код является только началом... но он должен получить вас на правильном пути

Ответ 2

django-session-security делает именно это...

... с дополнительным требованием: если сервер не отвечает или злоумышленник отключил интернет-соединение: он должен истечь в любом случае.

Disclamer: Я поддерживаю это приложение. Но я смотрел эту тему очень и очень долго:)

Ответ 3

Я просто совершенно новый, чтобы использовать Django.

Я хотел сделать сеанс завершенным, если зарегистрированный пользователь закроет браузер или находится в режиме ожидания (время бездействия) на некоторое время. Когда я разобрался в Google, этот вопрос SOF возник первым. Благодаря приятному ответу я искал ресурсы, чтобы понять, как работает middlewares во время цикла запросов/ответов в Django. Это было очень полезно.

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

SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True

Я не проверял другие браузеры, но хром. 1. Сессия закончилась, когда я закрыл браузер, даже если установлен SESSION_COOKIE_AGE. 2. Только когда я простаивал более 10 секунд, сеанс истек. Благодаря SESSION_SAVE_EVERY_REQUEST, всякий раз, когда вы выполняете новый запрос, он сохраняет сеанс и время ожидания обновлений до истечения срока действия

Чтобы изменить это поведение по умолчанию, установите для параметра SESSION_SAVE_EVERY_REQUEST значение True. Если установлено значение True, Django будет сохранять сеанс в базе данных при каждом отдельном запросе.

Обратите внимание, что cookie сеанса отправляется только тогда, когда сеанс был создан или изменен. Если SESSION_SAVE_EVERY_REQUEST имеет значение True, cookie сеанса будет отправляться по каждому запросу.

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

руководство django 1.10

Я просто оставляю ответ так, что некоторые люди, которые являются чем-то новым в Django, как я, не тратят много времени, чтобы найти решение так, как я сделал.

Ответ 4

Одним из простых способов удовлетворить ваше второе требование было бы установить значение SESSION_COOKIE_AGE в settings.py на подходящее количество секунд. Например:

SESSION_COOKIE_AGE = 600      #10 minutes.

Однако, только делая это, сеанс истечет через 10 минут независимо от того, демонстрирует ли пользователь какую-либо активность. Чтобы справиться с этой проблемой, срок действия может быть автоматически возобновлен (еще на дополнительные 10 минут) каждый раз, когда пользователь выполняет любой запрос со следующим предложением:

request.session.set_expiry(request.session.get_expiry_age())

Ответ 6

В первом запросе вы можете установить истечение сеанса как

self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds 

И при использовании access_key и токена

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page