Django: предупредите, когда пользователь войдет в систему?

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

  1. будьте уведомлены относительно пользовательского входа в систему/выхода из системы
  2. запросите пользовательское состояние входа в систему

С моей точки зрения идеальное решение было бы

  1. сигнал отправляется каждым django.contrib.auth.views.login и ... views.logout
  2. метод django.contrib.auth.models.User.is_logged_in(), аналогичный ... User.is_active() или ... User.is_authenticated()

У Django 1.1.1 нет этого, и я отказываюсь исправить источник и добавить его (не уверенный, как сделать это, так или иначе).

Как временное решение, я добавил is_logged_in булево поле к модели UserProfile, которая очищена по умолчанию, установлено в первый раз, когда пользователь поражает целевую страницу (определенный LOGIN_REDIRECT_URL = '/') и запрашивается в последующих запросах. Я добавил его к UserProfile, таким образом, я не должен произойти из и настроить встроенную модель User с этой целью только.

Мне не нравится это решение. Если пользователь explicitely нажимает кнопку выхода из системы, я могу очистить флаг, но большую часть времени, пользователи просто оставляют страницу или закрывают браузер; очистка флага в этих случаях не кажется прямой мне. Кроме того (это - мелочные придирки ясности довольно модели данных, хотя), is_logged_in не входит в состав UserProfile, но модели User.

Кто-либо может думать об альтернативных подходах?

74
задан Konrad Borowski 17 February 2018 в 23:14
поделиться

4 ответа

Одним из вариантов может быть обертывание представлений входа/выхода из системы Django вашими собственными. Например:

from django.contrib.auth.views import login, logout

def my_login(request, *args, **kwargs):
    response = login(request, *args, **kwargs)
    #fire a signal, or equivalent
    return response

def my_logout(request, *args, **kwargs):
    #fire a signal, or equivalent
    return logout(request, *args, **kwargs)

Затем вы используете эти представления в своем коде, а не в коде Django, и вуаля.

Что касается запроса статуса логина, то это довольно просто, если у вас есть доступ к объекту запроса; просто проверьте атрибут пользователя запроса, чтобы узнать, зарегистрированный ли он или анонимный, и бинго. Цитируя документацию Django:

if request.user.is_authenticated():
    # Do something for logged-in users.
else:
    # Do something for anonymous users.

Если у вас нет доступа к объекту запроса, то определить, зарегистрирован ли текущий пользователь, будет сложно.

Правка:

К сожалению, вы никогда не сможете получить функциональность User.is_logged_in() - это ограничение HTTP-протокола. Однако, если вы сделаете несколько предположений, то, возможно, сможете приблизиться к тому, что вам нужно.

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

Таким образом, у вас есть два варианта, которые не идеальны:

  1. Использовать событие Javascript unload, чтобы поймать, когда пользователь покидает страницу. Однако, Вы должны написать осторожную логику, чтобы убедиться, что Вы не выходите из системы, когда пользователь все еще навигационирует по Вашему сайту.
  2. Пробейте сигнал выхода всякий раз, когда пользователь входит в систему, просто чтобы быть уверенным. Также создайте задание cron, которое выполняется довольно часто, чтобы смыть просроченные сессии - когда просроченная сессия удаляется, проверьте, что у пользователя сессии (если он не анонимен) нет более активных сессий, и в этом случае вы запускаете сигнал выхода.

Эти решения грязные и не идеальные, но они - лучшее, что вы можете сделать, к сожалению.

.
13
ответ дан 24 November 2019 в 11:55
поделиться

Единственный надежный способ (который также определяет, когда пользователь закрыл браузер) - обновлять некоторое поле last_request каждый раз, когда пользователь загружает страницу.

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

Затем иметь одно фоновое задание, которое получает список последних пользователей, создает задания для них и очищает задания для пользователей, не присутствующих в этом списке.

.
1
ответ дан 24 November 2019 в 11:55
поделиться

Вывод из системы, в отличие от явного нажатия на кнопку (чего никто не делает), означает выбор времени простоя, которое равнозначно "выходу из системы". По умолчанию phpMyAdmin использует 15 минут, некоторые банковские сайты используют всего 5 минут.

Самым простым способом реализации этого параметра было бы изменение времени жизни cookie-файлов. Вы можете сделать это для всего вашего сайта, указав settings.SESSION_COOKIE_AGE. В качестве альтернативы, вы можете изменить его для каждого пользователя (на основе некоторого произвольного набора критериев), используя HttpResponse.setcookie(). Вы можете централизовать этот код, создав свою собственную версию render_to_response() и установив время жизни для каждого ответа.

.
1
ответ дан 24 November 2019 в 11:55
поделиться

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

.
0
ответ дан 24 November 2019 в 11:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: