Может понадобиться для какого-нибудь портала в интранете или чего-то такого секюрного.
Решается всё довольно банально, есть специальный сигнал
user_logged_in
.Ищем сессию для этого юзера, если нашли - сбрасываем в базе, сбрасываем в текущем engine (если это применимо).
Если что, у меня настроен один из стандартных:
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'Код обработчика сигнала. Всё заполонил комментариями, думаю, там всё понятно.
from django.contrib.auth.signals import user_logged_in from django.contrib import messages from django.contrib.sessions.models import Session from django.utils import timezone def user_logged_in_handler(sender, request, user, **kwargs): # текущая сессия: request.session.session_key for session in Session.objects.filter(expire_date__gte=timezone.now()).exclude(session_key=request.session.session_key): if session.get_decoded().get('_auth_user_id', None) == str(user.id): # нашли какую-то сессию, делаем её expired session.expire_date = timezone.now() session.save() # далее нам надо очистить все данные сессии # сначала я пробовал так # SessionStore = session.get_session_store_class() # sesstor = SessionStore(session.session_key) # sesstor.flush() # где flush - это метод именно для моего бекенда cached_db # я ожидал, что для модели вернётся текущий настроенный в settings.SESSION_ENGINE бекенд, но в модели Session захардкожено (как ни странно?) db.SessionStore # в принципе можно напрямую тупо импортировать cached_db.SessionStore, но сделал проще и универсальнее: # request.session у нас уже содержит установленный мидлварей нужный SessionStore # с помощью "чужой" нашей новой SessionStore удаляем левый наш старый session_key, там удачно есть такой даже метод request.session.delete(session.session_key) # раз у нас доступен request, то при желании показываем юзеру сообщение messages.add_message(request, messages.INFO, 'Была закрыта дублирующаяся сессия на каком-то другом компьютере') user_logged_in.connect(user_logged_in_handler)