Як закінчити сеанс через бездіяльність у Django?


93

У нашому додатку Django є такі вимоги до управління сеансом.

  1. Сесії закінчуються, коли користувач закриває веб-переглядач.
  2. Сесії закінчуються після періоду бездіяльності.
  3. Визначте, коли сеанс закінчується через неактивність, і покажіть користувачеві відповідне повідомлення.
  4. Попередити користувачів про наближається сеанс, який закінчується за кілька хвилин до закінчення періоду бездіяльності. Поряд із попередженням надайте користувачам можливість продовжити сеанс.
  5. Якщо користувач працює над тривалою діловою активністю в додатку, що не передбачає надсилання запитів на сервер, сеанс не повинен закінчуватися.

Прочитавши документацію, код Джанго та деякі публікації в блозі, пов’язані з цим, я придумав такий підхід до впровадження.

Вимога 1
Ця вимога легко реалізується, встановивши для SESSION_EXPIRE_AT_BROWSER_CLOSE значення True.

Вимога 2
Я побачив декілька рекомендацій використовувати SESSION_COOKIE_AGE для встановлення терміну закінчення сеансу. Але у цього методу є такі проблеми.

  • Сеанс завжди закінчується в кінці SESSION_COOKIE_AGE, навіть якщо користувач активно використовує додаток. (Це можна запобігти, встановивши термін дії сеансу на SESSION_COOKIE_AGE для кожного запиту за допомогою користувацького середнього програмного забезпечення або збереження сеансу для кожного запиту, встановивши SESSION_SAVE_EVERY_REQUEST на істинне. Але наступна проблема неминуча через використання 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).

Будь-яка інформація буде високо оцінена.


3
+1 за надання детального рішення
Дон

Існує проміжне програмне забезпечення, яке може робити все, що вам потрібно. on github and on pypi
gbutler

1
"Завдяки тому, як працюють файли cookie, SESSION_EXPIRE_AT_BROWSER_CLOSE та SESSION_COOKIE_AGE взаємно виключають, тобто файл cookie закінчується після закриття веб-переглядача або у вказаний термін дії. Якщо використовується SESSION_COOKIE_AGE, а користувач закриває браузер до закінчення терміну cookie, cookie буде відновлено. браузер дозволить користувачеві (або будь-кому іншому) входити в систему без повторної автентифікації. " Виправте мене, якщо я помиляюся, але це, здається, більше не відповідає дійсності в нових версіях Джанго? (Принаймні
1,5+

1
"Django покладається лише на певний файл cookie, щоб визначити, чи активний сеанс. Він не перевіряє дату закінчення сеансу, що зберігається під час сеансу." Це вже не так .
кнаперек

Відповіді:


44

Ось ідея ... Закінчіть сеанс у браузері, закрившись із 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']поточний час

Очевидно, що цей код є лише початком ... але він повинен вивести вас на правильний шлях


Я просто скептично ставлюсь тут, але не думаю, що if not request.is_ajax()це повністю безпечно. Чи не може хтось, хто отримує сеанс до закінчення сеансу підробки / відправляє дзвінок в Ajax і не продовжує сеанс?
notbad.jpeg

2
@ notbad.jpeg: загалом "активність" легко піддається підробці. Хтось, хто влаштовує сеанс і продовжує надсилати запити, просто активний.
RemcoGerlich

Це чудова відповідь. Посереднє програмне забезпечення - це недостатньо використаний інструмент розвитку Джанго.
Джеймі Конселл

30

Я просто новачок у використанні Джанго.

Я хотів, щоб сеанс закінчився, якщо зареєстрований користувач закрив браузер або перебуває в режимі очікування (час очікування бездіяльності) протягом певного часу. Коли я погукнув це, щоб розібратися, це питання SOF виникло першим. Завдяки приємній відповіді я переглянув ресурси, щоб зрозуміти, як працює середній рівень під час циклу запитів / відповідей у ​​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 вірно, cookie сеансу надсилатиметься під час кожного запиту.

Аналогічно, частина актуального файлу cookie сесії оновлюється щоразу, коли сеанс cookie надсилається.

посібник з джанго 1.10

Я просто залишаю відповідь, щоб деякі люди, які є новим в Джанго, як я, не витрачали багато часу на пошук рішення, як я.


26

django-session-security робить саме це ...

... з додатковою вимогою: якщо сервер не реагує або зловмисник відключив Інтернет-з'єднання: це має закінчитися в будь-якому разі.

Відмова: Я підтримую цю програму. Але я спостерігав цю тему дуже-дуже довго :)


1
класний додаток - чудово розроблений і добре побудований. приємний, чистий код ... дякую.
nicorellius

Якщо користувач закриває веб-переглядач або вкладку (не виходячи з системи), коли він / він виходить, чи все-таки примушує користувача вийти з системи? Чи справляється він із цим станом?
Мехмет Каган Каяальп

Це вирішиться шляхом закінчення терміну cookie сеансу чистого http, чи не так?
jpic

10

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

SESSION_COOKIE_AGE = 600      #10 minutes.

Однак, лише зробивши це, сеанс закінчується через 10 хвилин, незважаючи на те, що користувач проявляє деяку активність. Щоб вирішити цю проблему, час закінчення терміну дії можна автоматично поновити (ще на додаткові 10 хвилин) щоразу, коли користувач виконує будь-який запит із наступним реченням:

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

2
SESSION_COOKIE_AGE = 600 Це збільшить вік сеансів із кожним запитом на нову сторінку або оновлення сторінки
Aseem

1
Я підтверджую, що достатньо лише встановити налаштування SESSION_COOKIE_AGEі що будь-який запит (надсилання сеансового файлу cookie) автоматично оновить закінчення сеансового файлу cookie.
bruno desthuilliers


3

У першому запиті ви можете встановити термін дії сеансу як

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

І коли ви використовуєте ключ доступу та ключ,

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.