Хоча відповідь Гарольда працює в цьому конкретному випадку, я бачу принаймні дві важливі проблеми:
- Це рішення можна використовувати лише з механізмом сеансу бази даних . В інших ситуаціях (кеш, файл, 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()