Wie läuft die Sitzung aufgrund von Inaktivität in Django ab?

93

Unsere Django-Anwendung hat die folgenden Anforderungen an das Sitzungsmanagement.

  1. Sitzungen laufen ab, wenn der Benutzer den Browser schließt.
  2. Sitzungen laufen nach einer Zeit der Inaktivität ab.
  3. Erkennen Sie, wann eine Sitzung aufgrund von Inaktivität abläuft, und zeigen Sie dem Benutzer die entsprechende Meldung an.
  4. Warnen Sie Benutzer vor dem bevorstehenden Ablauf einer Sitzung einige Minuten vor dem Ende des Inaktivitätszeitraums. Bieten Sie den Benutzern zusammen mit der Warnung die Option, ihre Sitzung zu verlängern.
  5. Wenn der Benutzer an einer langen Geschäftsaktivität in der App arbeitet, bei der keine Anforderungen an den Server gesendet werden, darf die Sitzung keine Zeitüberschreitung aufweisen.

Nachdem ich die Dokumentation, den Django-Code und einige diesbezügliche Blog-Beiträge gelesen habe, habe ich den folgenden Implementierungsansatz entwickelt.

Anforderung 1
Diese Anforderung kann einfach implementiert werden, indem SESSION_EXPIRE_AT_BROWSER_CLOSE auf True gesetzt wird.

Anforderung 2
Ich habe einige Empfehlungen zur Verwendung von SESSION_COOKIE_AGE zum Festlegen des Sitzungsablaufzeitraums gesehen. Diese Methode weist jedoch die folgenden Probleme auf.

  • Die Sitzung läuft immer am Ende der SESSION_COOKIE_AGE ab, auch wenn der Benutzer die Anwendung aktiv verwendet. (Dies kann verhindert werden, indem der Sitzungsablauf bei jeder Anforderung mit einer benutzerdefinierten Middleware auf SESSION_COOKIE_AGE gesetzt wird oder indem die Sitzung bei jeder Anforderung durch Setzen von SESSION_SAVE_EVERY_REQUEST auf true gespeichert wird. Das nächste Problem ist jedoch aufgrund der Verwendung von SESSION_COOKIE_AGE unvermeidbar.)

  • Aufgrund der Funktionsweise von Cookies schließen sich SESSION_EXPIRE_AT_BROWSER_CLOSE und SESSION_COOKIE_AGE gegenseitig aus, dh das Cookie läuft entweder beim Schließen des Browsers oder zum angegebenen Ablaufzeitpunkt ab. Wenn SESSION_COOKIE_AGE verwendet wird und der Benutzer den Browser schließt, bevor das Cookie abläuft, wird das Cookie beibehalten und durch erneutes Öffnen des Browsers kann der Benutzer (oder eine andere Person) das System betreten, ohne erneut authentifiziert zu werden.

  • Django verlässt sich nur darauf, dass das Cookie vorhanden ist, um festzustellen, ob die Sitzung aktiv ist. Das mit der Sitzung gespeicherte Ablaufdatum der Sitzung wird nicht überprüft.

Die folgende Methode könnte verwendet werden, um diese Anforderung zu implementieren und die oben genannten Probleme zu umgehen.

  • Setzen Sie nicht SESSION_COOKIE_AGE.
  • Stellen Sie das Ablaufdatum der Sitzung bei jeder Anforderung auf "Aktuelle Zeit + Inaktivitätszeitraum" ein.
  • Überschreiben Sie process_request in SessionMiddleware und überprüfen Sie, ob die Sitzung abgelaufen ist. Verwerfen Sie die Sitzung, wenn sie abgelaufen ist.

Anforderung 3
Wenn wir feststellen, dass die Sitzung abgelaufen ist (in der benutzerdefinierten SessionMiddleware oben), legen Sie in der Anforderung ein Attribut fest, um den Ablauf der Sitzung anzuzeigen. Dieses Attribut kann verwendet werden, um dem Benutzer eine entsprechende Nachricht anzuzeigen.

Anforderung 4
Verwenden Sie JavaScript, um Benutzerinaktivität zu erkennen, die Warnung bereitzustellen und die Sitzung zu verlängern. Wenn der Benutzer verlängern möchte, senden Sie einen Keep-Alive-Impuls an den Server, um die Sitzung zu verlängern.

Anforderung 5
Verwenden Sie JavaScript, um Benutzeraktivitäten (während des langen Geschäftsbetriebs) zu erkennen und Keep-Alive-Impulse an den Server zu senden, um zu verhindern, dass die Sitzung abläuft.


Der obige Implementierungsansatz scheint sehr aufwendig zu sein, und ich habe mich gefragt, ob es eine einfachere Methode geben könnte (insbesondere für Anforderung 2).

Alle Erkenntnisse werden sehr geschätzt.

Akbar ibrahim
quelle
3
+1 für die Bereitstellung einer detaillierten Lösung
Don
Es gibt eine Middleware, die möglicherweise das tut, was Sie benötigen. auf Github und auf Pypi
Gbutler
1
"Aufgrund der Funktionsweise von Cookies schließen sich SESSION_EXPIRE_AT_BROWSER_CLOSE und SESSION_COOKIE_AGE gegenseitig aus, dh das Cookie läuft entweder beim Schließen des Browsers oder zum angegebenen Ablaufzeitpunkt ab. Wenn SESSION_COOKIE_AGE verwendet wird und der Benutzer den Browser schließt, bevor das Cookie abläuft, wird das Cookie beibehalten und erneut geöffnet Der Browser lässt den Benutzer (oder andere Personen) in das System ein, ohne erneut authentifiziert zu werden. " Korrigieren Sie mich, wenn ich falsch liege, aber dies scheint in neueren Django-Versionen nicht mehr zuzutreffen? (Mindestens 1,5+)
Botond Béres
1
"Django verlässt sich nur darauf, dass das Cookie vorhanden ist, um festzustellen, ob die Sitzung aktiv ist. Es überprüft nicht das in der Sitzung gespeicherte Ablaufdatum der Sitzung." Das stimmt nicht mehr.
Knaperek

Antworten:

44

Hier ist eine Idee ... Lassen Sie die Sitzung im Browser mit der SESSION_EXPIRE_AT_BROWSER_CLOSEEinstellung schließen. Setzen Sie dann bei jeder Anfrage einen Zeitstempel in der Sitzung.

request.session['last_activity'] = datetime.now()

und fügen Sie eine Middleware hinzu, um festzustellen, ob die Sitzung abgelaufen ist. so etwas sollte den gesamten Prozess abwickeln ...

from datetime import datetime
from django.http import HttpResponseRedirect

class SessionExpiredMiddleware:
    def process_request(request):
        last_activity = request.session['last_activity']
        now = datetime.now()

        if (now - last_activity).minutes > 10:
            # Do logout / expire session
            # and then...
            return HttpResponseRedirect("LOGIN_PAGE_URL")

        if not request.is_ajax():
            # don't set this for ajax requests or else your
            # expired session checks will keep the session from
            # expiring :)
            request.session['last_activity'] = now

Dann müssen Sie nur noch einige URLs und Ansichten erstellen, um relevante Daten bezüglich des Sitzungsablaufs an die Ajax-Aufrufe zurückzugeben.

Wenn der Benutzer die Sitzung sozusagen "erneuert", müssen Sie lediglich requeset.session['last_activity']die aktuelle Zeit erneut einstellen

Natürlich ist dieser Code nur ein Anfang ... aber er sollte Sie auf den richtigen Weg bringen

Jiaaro
quelle
Ich bin hier nur skeptisch, aber ich denke nicht, dass das if not request.is_ajax()völlig sicher ist. Kann nicht jemand, der die Parodie vor Ablauf der Sitzung in den Griff bekommt, einen Ajax-Anruf senden und die Sitzung am Laufen halten?
notbad.jpeg
2
@ notbad.jpeg: Im Allgemeinen ist "Aktivität" leicht fälschbar. Jemand, der die Sitzung abruft und weiterhin Anfragen sendet, ist nur aktiv.
RemcoGerlich
Dies ist eine großartige Antwort. Middleware ist ein sehr wenig genutztes Tool in der Django-Entwicklung.
Jamie Counsell
30

Ich bin gerade ziemlich neu, um Django zu benutzen.

Ich wollte, dass die Sitzung abläuft, wenn der angemeldete Benutzer den Browser schließt oder sich für einige Zeit im Leerlauf befindet (Zeitlimit für Inaktivität). Als ich es gegoogelt habe, um es herauszufinden, kam diese SOF-Frage zuerst auf. Dank der netten Antwort habe ich nach Ressourcen gesucht, um zu verstehen, wie Middleware während des Anforderungs- / Antwortzyklus in Django funktioniert. Es war sehr hilfreich.

Ich wollte gerade benutzerdefinierte Middleware in meinen Code anwenden, nachdem ich hier die beste Antwort gegeben hatte. Aber ich war immer noch ein bisschen misstrauisch, weil die beste Antwort hier im Jahr 2011 bearbeitet wurde. Ich nahm mir mehr Zeit, um ein bisschen nach den letzten Suchergebnissen zu suchen, und fand einen einfachen Weg.

SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True

Ich habe keine anderen Browser als Chrome überprüft. 1. Eine Sitzung ist abgelaufen, als ich einen Browser geschlossen habe, auch wenn SESSION_COOKIE_AGE festgelegt wurde. 2. Nur wenn ich länger als 10 Sekunden im Leerlauf war, ist eine Sitzung abgelaufen. Dank SESSION_SAVE_EVERY_REQUEST wird bei jeder neuen Anforderung die Sitzung gespeichert und das Zeitlimit für Aktualisierungen wird abgelaufen

Um dieses Standardverhalten zu ändern, setzen Sie die Einstellung SESSION_SAVE_EVERY_REQUEST auf True. Wenn True festgelegt ist, speichert Django die Sitzung bei jeder einzelnen Anforderung in der Datenbank.

Beachten Sie, dass das Sitzungscookie nur gesendet wird, wenn eine Sitzung erstellt oder geändert wurde. Wenn SESSION_SAVE_EVERY_REQUEST True ist, wird das Sitzungscookie bei jeder Anforderung gesendet.

Ebenso wird der abgelaufene Teil eines Sitzungscookies jedes Mal aktualisiert, wenn das Sitzungscookie gesendet wird.

Django Handbuch 1.10

Ich lasse nur die Antwort, damit einige Leute, die in Django so neu wie ich sind, nicht viel Zeit damit verbringen, eine Lösung zu finden, wie ich es getan habe.

Jayground
quelle
26

django-session-security macht genau das ...

... mit einer zusätzlichen Anforderung: Wenn der Server nicht antwortet oder ein Angreifer die Internetverbindung getrennt hat, sollte sie trotzdem ablaufen.

Disclamer: Ich pflege diese App. Aber ich habe diesen Thread sehr, sehr lange gesehen :)

jpic
quelle
1
coole App - schön gestaltet und gut gebaut. netter, sauberer Code ... danke.
Nicorellius
Wenn der Benutzer den Browser oder die Registerkarte (ohne sich abzumelden) beim Verlassen schließt, wird der Benutzer dann immer noch zum Abmelden gezwungen? Behandelt es diesen Zustand?
Mehmet Kagan Kayaalp
Das würde durch den Ablauf von Pure-http-Sitzungscookies erledigt, nicht wahr?
JPIC
10

Eine einfache Möglichkeit, Ihre zweite Anforderung zu erfüllen, besteht darin, den Wert SESSION_COOKIE_AGE in settings.py auf eine geeignete Anzahl von Sekunden festzulegen. Zum Beispiel:

SESSION_COOKIE_AGE = 600      #10 minutes.

Wenn Sie dies jedoch nur tun, läuft die Sitzung nach 10 Minuten ab, unabhängig davon, ob der Benutzer eine Aktivität aufweist oder nicht. Um dieses Problem zu beheben, kann die Ablaufzeit jedes Mal automatisch verlängert werden (um weitere 10 Minuten), wenn der Benutzer eine Anforderung mit dem folgenden Satz ausführt:

request.session.set_expiry(request.session.get_expiry_age())
Fernando Martin
quelle
2
SESSION_COOKIE_AGE = 600 Dies verlängert das Sitzungsalter mit jeder neuen Seitenanforderung oder
Seitenaktualisierung
1
Ich bestätige, dass nur die Einstellung SESSION_COOKIE_AGEausreicht und dass jede Anforderung (Senden des Sitzungscookies) den Ablauf des Sitzungscookies automatisch aktualisiert.
Bruno Desthuilliers
3

Sie können auch integrierte Stackoverflow-Funktionen verwenden

SESSION_SAVE_EVERY_REQUEST = True
mexekanez
quelle
Völlig unabhängig - Dies dient dazu, bei jeder Anforderung ein Speichern der Sitzung (nicht "Aktualisieren des Sitzungscookies") zu erzwingen, ohne zu überprüfen, ob die Sitzung geändert wurde.
Bruno Desthuilliers
3

In der ersten Anforderung können Sie den Sitzungsablauf als festlegen

self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds 

Und wenn Sie den access_key und das Token verwenden,

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page
Tilaprimera
quelle