In meiner Django-App möchte ich unter bestimmten Bedingungen Benutzer dazu zwingen können, sich mit einem Benutzernamen abzumelden. Nicht unbedingt der aktuelle Benutzer, der angemeldet ist, sondern ein anderer Benutzer. Daher enthält die Anforderungsmethode in meiner Ansicht keine Sitzungsinformationen zu dem Benutzer, den ich abmelden möchte.
Ich bin mit django.auth und mit auth vertraut. Abmeldemethode, aber es nimmt Anfrage als Argument. Gibt es einen "Django-Weg", um den Benutzer abzumelden, wenn ich nur den Benutzernamen habe? Oder muss ich mein eigenes Abmelde-SQL rollen?
django
django-authentication
Sergey Golovchenko
quelle
quelle
user.session_set.all().delete()
. Haftungsausschluss: Ich bin der Autor von Django-Qsessions.Antworten:
Ich glaube, es gibt noch keinen sanktionierten Weg, dies in Django zu tun.
Die Benutzer-ID wird im Sitzungsobjekt gespeichert, jedoch codiert. Leider bedeutet dies, dass Sie alle Sitzungen durchlaufen, dekodieren und vergleichen müssen ...
Zwei schritte:
Löschen Sie zuerst die Sitzungsobjekte für Ihren Zielbenutzer. Wenn sie sich von mehreren Computern aus anmelden, verfügen sie über mehrere Sitzungsobjekte.
from django.contrib.sessions.models import Session from django.contrib.auth.models import User # grab the user in question user = User.objects.get(username='johndoe') [s.delete() for s in Session.objects.all() if s.get_decoded().get('_auth_user_id') == user.id]
Dann, wenn Sie müssen, sperren Sie sie aus ....
user.is_active = False user.save()
quelle
Obwohl Harolds Antwort in diesem speziellen Fall funktioniert, kann ich mindestens zwei wichtige Probleme damit erkennen:
Session
Modell nicht verwendet.Um diese Probleme zu lösen, schlage ich vor, dass Sie das Problem anders angehen. Die Idee ist, irgendwo das Datum zu speichern, an dem der Benutzer für eine bestimmte Sitzung angemeldet war, und das letzte Mal, als Sie einen Benutzer zum Abmelden aufgefordert haben.
Dann , wenn jemand Zugriff auf Ihrer Website, wenn das Datum angemeldet ist niedriger als das Abmeldedatum, können Sie zwangsAbmelde den Benutzer. Wie Dan sagte, gibt es keinen praktischen Unterschied zwischen dem sofortigen Abmelden eines Benutzers oder seiner nächsten Anfrage an Ihre Site.
Lassen Sie uns nun eine mögliche Implementierung dieser Lösung für django 1.3b1 sehen . In drei Schritten:
1. Speichern Sie in der Sitzung das letzte Anmeldedatum
Glücklicherweise gibt das Django-Authentifizierungssystem ein Signal aus, das aufgerufen wird
user_logged_in
. Sie müssen nur diese Signale registrieren und das aktuelle Datum in der Sitzung speichern. Am Ende Ihresmodels.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. Fordern Sie eine Force-Abmeldung für einen Benutzer an
Wir müssen dem
User
Modell nur ein Feld und eine Methode hinzufügen . Es gibt mehrere Möglichkeiten, dies zu erreichen ( Benutzerprofile , Modellvererbung usw.), die jeweils Vor- und Nachteile haben.Der Einfachheit halber werde ich hier die Modellvererbung verwenden. Wenn Sie sich für diese Lösung entscheiden, vergessen Sie nicht , ein benutzerdefiniertes Authentifizierungs-Backend zu schreiben .
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()
Wenn Sie dann die Abmeldung für den Benutzer erzwingen möchten
johndoe
, müssen Sie nur:from myapp.models import MyUser MyUser.objects.get(username='johndoe').force_logout()
3. Implementieren Sie die Zugriffsprüfung
Der beste Weg hier ist, eine Middleware zu verwenden, wie Dan vorgeschlagen hat. Diese Middleware zugreifen
request.user
, also setzen Sie sie brauchen , um nach'django.contrib.auth.middleware.AuthenticationMiddleware'
IhrerMIDDLEWARE_CLASSES
Einstellung.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)
Das sollte es tun.
Anmerkungen
JOIN
. Durch die Verwendung von Benutzerprofilen wird eine zusätzliche Abfrage hinzugefügt. Direktes ÄndernUser
ist der beste Weg, um die Leistung zu verbessern, aber es ist immer noch ein haariges Thema .Wenn Sie diese Lösung auf einer vorhandenen Site bereitstellen, haben Sie wahrscheinlich Probleme mit vorhandenen Sitzungen, die nicht über den
'LAST_LOGIN_DATE'
Schlüssel verfügen . Sie können den Middleware-Code ein wenig anpassen, um diesen Fall zu behandeln: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)
In Django 1.2.x gibt es kein
user_logged_in
Signal. Zurückgreifen auf das Überschreiben derlogin
Funktion: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()
quelle
Ich brauchte etwas Ähnliches in meiner App. In meinem Fall, wenn ein Benutzer auf inaktiv gesetzt war, wollte ich sicherstellen, dass der Benutzer abgemeldet ist und die Site nicht weiter nutzen kann, wenn er bereits angemeldet war. Nachdem ich diesen Beitrag gelesen hatte, kam ich zu folgender Lösung:
from django.contrib.auth import logout class ActiveUserMiddleware(object): def process_request(self, request): if not request.user.is_authenticated: return if not request.user.is_active: logout(request)
Fügen Sie diese Middleware einfach in Ihre Einstellungen ein und los geht's. Wenn Sie Kennwörter ändern, können Sie ein neues Feld in das Benutzerprofilmodell einfügen, das einen Benutzer zum Abmelden zwingt, den Wert des Felds anstelle von is_active oben überprüft und das Feld auch deaktiviert, wenn sich ein Benutzer anmeldet. Letzteres kann mit Djangos user_logged_in Signal gemacht werden.
quelle
if request.user.is_authenticated() and not request.user.is_active
Vielleicht ein bisschen Middleware, die auf eine Liste von Benutzern verweist, die gezwungen waren, sich abzumelden. Wenn der Benutzer das nächste Mal versucht, etwas zu tun, melden Sie sie dann ab, leiten Sie sie um usw.
Es sei denn natürlich, sie müssen sofort abgemeldet werden. Andererseits würden sie es erst bemerken, wenn sie das nächste Mal versuchten, eine Anfrage zu stellen, sodass die oben genannte Lösung möglicherweise einfach funktioniert.
quelle
Dies ist eine Antwort auf Balons Anfrage:
Ja, mit ungefähr 140.000 Sitzungen kann ich sehen, warum Harolds Antwort möglicherweise nicht so schnell ist, wie Sie möchten!
Ich würde empfehlen, ein Modell hinzuzufügen, dessen einzige zwei Eigenschaften Fremdschlüssel
User
undSession
Objekte sind. Fügen Sie dann eine Middleware hinzu, die dieses Modell mit den aktuellen Benutzersitzungen auf dem neuesten Stand hält. Ich habe diese Art von Setup schon einmal verwendet. In meinem Fall habe ich dassessionprofile
Modul von diesem Single Sign-On-System für phpBB ausgeliehen (siehe Quellcode im Ordner "django / sessionprofile") und dies (glaube ich) würde Ihren Anforderungen entsprechen.Am Ende würden Sie irgendwo in Ihrem Code eine Verwaltungsfunktion wie diese haben (unter der Annahme der gleichen Codenamen und des gleichen Layouts wie im
sessionprofile
oben verlinkten Modul):from sessionprofile.models import SessionProfile from django.contrib.auth.models import User # Find all SessionProfile objects corresponding to a given username sessionProfiles = SessionProfile.objects.filter(user__username__exact='johndoe') # Delete all corresponding sessions [sp.session.delete() for sp in sessionProfiles]
(Ich denke, dies wird auch die
SessionProfile
Objekte löschen. Soweit ich mich erinnere, besteht Djangos Standardverhalten beimForeignKey
Löschen eines Objekts, auf das von a verwiesen wird, darin, es zu kaskadieren und auch das Objekt zu löschen, das das enthält.ForeignKey
Wenn nicht, ist es trivial genug, das zu löschen Inhalt,sessionProfiles
wenn Sie fertig sind.)quelle
Als Tony Abou-Assaleh musste ich auch Benutzer abmelden, die auf inaktiv eingestellt waren, und begann mit der Implementierung seiner Lösung. Nach einiger Zeit stellte ich fest, dass die Middleware bei allen Anforderungen eine DB-Abfrage erzwingt (um zu überprüfen, ob der Benutzer blockiert wurde) und somit die Leistung auf Seiten beeinträchtigt, für die keine Anmeldung erforderlich ist.
Ich habe ein benutzerdefiniertes Benutzerobjekt und Django> = 1.7. Am Ende habe ich also seine
get_session_auth_hash
Funktion überschrieben , um die Sitzung ungültig zu machen, wenn der Benutzer inaktiv ist. Eine mögliche Implementierung ist:def get_session_auth_hash(self): if not self.is_active: return "inactive" return super(MyCustomUser, self).get_session_auth_hash()
Damit dies funktioniert,
django.contrib.auth.middleware.SessionAuthenticationMiddleware
sollte in seinsettings.MIDDLEWARE_CLASSES
quelle
Sie können dazu auch die direkte Django-Funktion verwenden. Sie aktualisiert und protokolliert alle anderen Sitzungen für den Benutzer mit Ausnahme der aktuellen.
from django.contrib.auth import update_session_auth_hash update_session_auth_hash(self.request, user)
Dokumente für update_session_auth_hash hier .
quelle
Wie bereits erwähnt, können Sie alle Sitzungen in der Datenbank durchlaufen, alle dekodieren und die Sitzungen dieses Benutzers löschen. Aber es ist langsam, besonders wenn Ihre Site viel Verkehr hat und es viele Sitzungen gibt.
Wenn Sie eine schnellere Lösung benötigen, können Sie ein Sitzungs-Backend verwenden, mit dem Sie die Sitzungen eines bestimmten Benutzers abfragen und abrufen können. In diesen Sitzungs-Backends verfügt die Sitzung über einen Fremdschlüssel für den Benutzer, sodass Sie nicht alle Sitzungsobjekte durchlaufen müssen:
db
,cached_db
Sitzung Backends)db
Session-Backend von Django )Mit diesen Backends können Sie alle Sitzungen eines Benutzers in einer einzigen Codezeile löschen:
Haftungsausschluss: Ich bin der Autor von
django-qsessions
.quelle
aus django.contrib.sessions.models Sitzung importieren
Benutzersitzung löschen
[s.delete() for s in Session.objects.all() if s.get_decoded().get('_auth_user_hash') == user.get_session_auth_hash()]
quelle
Sogar ich habe mich diesem Problem gestellt. Nur wenige Spammer aus Indien veröffentlichen immer wieder Informationen über diese Baba und Molvi für Liebeslösungen.
Was ich getan habe, war zum Zeitpunkt der Veröffentlichung gerade diesen Code eingefügt:
if request.user.is_active==False: return HttpResponse('You are banned on the site for spaming.')
quelle