Bien que la réponse d'Harold fonctionne dans ce cas précis, je vois au moins deux problèmes importants avec elle :
- Cette solution ne peut être utilisée qu'avec une base de données moteur de session . Dans d'autres situations (cache, fichier, cookie), l'option
Session
ne serait pas utilisé.
- Lorsque le nombre de sessions et d'utilisateurs dans la base de données augmente, cela devient assez inefficace.
Pour résoudre ces problèmes, je vous suggère d'adopter une autre approche du problème. L'idée est de stocker quelque part la date à laquelle l'utilisateur a été connecté pour une session donnée, et la dernière fois que vous avez demandé à un utilisateur d'être déconnecté.
Ensuite, chaque fois que quelqu'un accède à votre site, si la date d'ouverture de session est plus bas que la date de déconnexion, vous pouvez forcer la déconnexion de l'utilisateur. Comme l'a dit Dan, il n'y a pas de différence pratique entre déconnecter un utilisateur immédiatement ou lors de sa prochaine visite sur votre site.
Maintenant, voyons une mise en œuvre possible de cette solution, pour django 1.3b1 . En trois étapes :
1. stocker dans la session la date de la dernière connexion
Heureusement, le système d'authentification de Django expose une fonction signal appelé user_logged_in
. Il suffit d'enregistrer ces signaux, et de sauvegarder la date actuelle dans la session. Au bas de votre 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. demander une déconnexion forcée pour un utilisateur
Il nous suffit d'ajouter un champ et une méthode à l'interface de l'utilisateur. User
modèle. Il y a plusieurs façons d'y parvenir ( profils d'utilisateurs , l'héritage du modèle ), chacun ayant ses avantages et ses inconvénients.
Pour des raisons de simplicité, je vais utiliser l'héritage de modèle ici, si vous optez pour cette solution, n'oubliez pas de écrire un backend d'authentification personnalisé .
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()
Ensuite, si vous voulez forcer la déconnexion pour l'utilisateur johndoe
vous n'avez qu'à le faire :
from myapp.models import MyUser
MyUser.objects.get(username='johndoe').force_logout()
3. mettre en œuvre le contrôle d'accès
La meilleure façon de procéder est d'utiliser un intergiciel comme l'a suggéré Dan. Cet intergiciel accédera request.user
donc tu dois le mettre après 'django.contrib.auth.middleware.AuthenticationMiddleware'
dans votre MIDDLEWARE_CLASSES
réglage.
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)
Ça devrait le faire.
Notes
-
Soyez conscient de l'impact sur les performances du stockage d'un champ supplémentaire pour vos utilisateurs. L'utilisation de l'héritage de modèle ajoutera un champ JOIN
. L'utilisation de profils d'utilisateurs ajoutera une requête supplémentaire. Modifier directement le User
est la meilleure solution en termes de performances, mais il s'agit toujours d'un système de gestion de la qualité. sujet poilu .
-
Si vous déployez cette solution sur un site existant, vous aurez probablement quelques difficultés avec les sessions existantes, qui n'auront pas le 'LAST_LOGIN_DATE'
clé. Vous pouvez adapter un peu le code du middleware pour traiter ce cas :
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)
-
Dans django 1.2.x, il n'y a pas de user_logged_in
signal. Revenir à l'annulation de la login
fonction :
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()
0 votes
Pourquoi voulez-vous déconnecter un utilisateur autre que celui qui s'est connecté ? Si vous utilisez des sessions de longueur navigateur, les utilisateurs qui ne sont pas connectés sont déjà déconnectés.
3 votes
Disons que je dois déconnecter l'utilisateur lorsque le mot de passe a été modifié. J'ai plus de 100 000 utilisateurs et environ 140 000 sessions dans la table des sessions. Comment gérer cela efficacement ?
1 votes
@kjagiello Jetez un coup d'oeil à github.com/QueraTeam/django-qsessions backend. En l'utilisant, vous pouvez facilement déconnecter un utilisateur :
user.session_set.all().delete()
. Disclaimer : Je suis l'auteur de django-qsessions.