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