Хотя ответ Гарольда работает в этом конкретном случае, я вижу в нем как минимум две важные проблемы:
- Это решение можно использовать только с сеансом базы данных двигатель. В других ситуациях (кеш, файл, cookie) модель
Session
использоваться не будет.
- Когда количество сеансов и пользователей в базе данных растет, это становится совершенно неэффективным.
Чтобы решить эти проблемы, я предлагаю вам использовать другой подход к проблеме. Идея состоит в том, чтобы где-то сохранить дату, когда пользователь вошел в систему для данного сеанса, и последний раз, когда вы запрашивали выход пользователя из системы.
Затем, когда кто-либо заходит на ваш сайт, если дата входа в систему ниже даты выхода, вы можете принудительно выйти из системы. Как сказал Дэн, нет никакой практической разницы между немедленным выходом пользователя из системы или его следующим запросом на ваш сайт.
Теперь давайте посмотрим на возможную реализацию этого решения для django 1.3b1. В три этапа:
1. сохранить в сеансе дату последнего входа в систему
К счастью, система аутентификации Django предоставляет сигнал, называемый user_logged_in
. Вам просто нужно зарегистрировать эти сигналы и сохранить текущую дату в сеансе. Внизу вашего models.py
:
from django.contrib.auth.signals import user_logged_in
from datetime import datetime
def update_session_last_login(sender, user=user, request=request, **kwargs):
if request:
request.session['LAST_LOGIN_DATE'] = datetime.now()
user_logged_in.connect(update_session_last_login)
2. запросить принудительный выход для пользователя
Нам просто нужно добавить поле и метод к модели User
. Есть несколько способов добиться этого (профили пользователей, наследование модели и т. д.) у каждого свои плюсы и минусы.
Для простоты я буду использовать здесь наследование модели. Если вы выберете это решение, не забудьте указать написать собственный сервер аутентификации.
from django.contrib.auth.models import User
from django.db import models
from datetime import datetime
class MyUser(User):
force_logout_date = models.DateTimeField(null=True, blank=True)
def force_logout(self):
self.force_logout_date = datetime.now()
self.save()
Затем, если вы хотите принудительно выйти из системы для пользователя johndoe
, вам просто нужно:
from myapp.models import MyUser
MyUser.objects.get(username='johndoe').force_logout()
3. реализовать проверку доступа
Лучший способ здесь - использовать промежуточное ПО, как было предложено Даном. Это промежуточное ПО будет обращаться к request.user
, поэтому вам нужно указать его после 'django.contrib.auth.middleware.AuthenticationMiddleware'
в настройках MIDDLEWARE_CLASSES
.
from django.contrib.auth import logout
class ForceLogoutMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated() and request.user.force_logout_date and \
request.session['LAST_LOGIN_DATE'] < request.user.force_logout_date:
logout(request)
Это должно сработать.
Примечания
- Помните о влиянии на производительность хранения дополнительного поля для ваших пользователей. Использование наследования модели добавит дополнительный
JOIN
. Использование профилей пользователей добавит дополнительный запрос. Прямое изменение User
- лучший способ повысить производительность, но это все еще неоднозначная тема.
Если вы развернете это решение на существующем сайте, у вас, вероятно, возникнут проблемы с существующими сеансами, в которых не будет ключа 'LAST_LOGIN_DATE'
. Вы можете немного адаптировать код промежуточного программного обеспечения, чтобы справиться с этим случаем:
from django.contrib.auth import logout
class ForceLogoutMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated() and request.user.force_logout_date and \
( 'LAST_LOGIN_DATE' not in request.session or \
request.session['LAST_LOGIN_DATE'] < request.user.force_logout_date ):
logout(request)
В django 1.2.x нет сигнала user_logged_in
. Вернитесь к переопределению функции login
:
from django.contrib.auth import login as dj_login
from datetime import datetime
def login(request, user):
dj_login(request, user)
request.session['LAST_LOGIN_DATE'] = datetime.now()
person
Clément
schedule
20.02.2011
user.session_set.all().delete()
. Отказ от ответственности: я являюсь автором django-qsessions. - person Mohammad Javad Naderi   schedule 10.11.2019