5 Stimmen

Wie stelle ich fest, wenn ein Benutzer eine Leerlaufzeit in Django hat?

Ich möchte überprüfen, wenn ein Benutzer ein Leerlauf-Timeout in meiner Django-Anwendung erlebt hat. Mit anderen Worten, wenn das Ablaufdatum des Sitzungscookies des Benutzers das SESSION_COOKIE_AGE in settings.py überschreitet, wird der Benutzer auf die Anmeldeseite umgeleitet. Wenn dies geschieht, sollte auch ein Audit stattfinden. Mit "Audit" meine ich, dass ein Datensatz in meine person.audit-Tabelle geschrieben werden sollte.

Derzeit habe ich eine Middleware zur Erfassung dieser Ereignisse konfiguriert. Leider generiert Django ein neues Cookie, wenn der Benutzer auf die Anmeldeseite umgeleitet wird, so dass ich nicht feststellen kann, ob der Benutzer über ein Leerlauf-Timeout oder ein anderes Ereignis auf die Anmeldeseite geleitet wurde.

Soweit ich das beurteilen kann, müsste ich mit der Tabelle "django_session" arbeiten. Die Datensätze in dieser Tabelle können jedoch nicht mit diesem Benutzer verknüpft werden, da der sessionid-Wert im Cookie zurückgesetzt wird, wenn die Umleitung erfolgt.

Ich vermute, dass ich nicht der Erste bin, der mit diesem Dilemma konfrontiert ist. Hat jemand eine Idee, wie das Problem zu lösen ist?

0 Stimmen

Was meinen Sie damit, dass Sie es prüfen wollen? Sie meinen, es zu protokollieren? Ehrlich gesagt, verstehe ich nicht ganz, was Sie vorhaben, können Sie das etwas näher erläutern?

0 Stimmen

Die Benutzer können das System auf zwei Arten verlassen: Sie können auf einen Abmeldelink klicken oder ihre Sitzung kann ablaufen (nach 60 Minuten). Ich muss beide Fälle protokollieren (auch bekannt als "Audit").

9voto

elo80ka Punkte 13417

Aktualisierung:

Nach einigen Tests habe ich festgestellt, dass der unten stehende Code Ihre Frage nicht beantwortet. Obwohl es funktioniert, und das Signal-Handler wird aufgerufen, prev_session_data wenn sie existiert, keine nützlichen Informationen enthält.

Zunächst ein Blick auf den Sitzungsrahmen:

  1. Wenn ein neuer Besucher eine Anwendungs-URL anfordert, wird eine neue Sitzung für ihn erstellt - zu diesem Zeitpunkt ist er noch anonym ( request.user ist eine Instanz von AnonymousUser).
  2. Wenn sie eine Ansicht anfordern, die eine Authentifizierung erfordert, werden sie zur Login-Ansicht weitergeleitet.
  3. Wenn die Login-Ansicht angefordert wird, wird ein Testwert in der Sitzung des Benutzers gesetzt ( SessionStore._session ); dies setzt automatisch die accessed y modified Flaggen der aktuellen Sitzung.
  4. Während der Antwortphase der oben genannten Anfrage wird die SessionMiddleware speichert die aktuelle Sitzung und erstellt damit eine neue Session Instanz in der django_session Tabelle (wenn Sie die standardmäßigen datenbankgestützten Sitzungen verwenden, die von django.contrib.sessions.backends.db ). Die ID der neuen Sitzung wird in der Datei settings.SESSION_COOKIE_NAME Keks.
  5. Wenn der Benutzer seinen Benutzernamen und sein Passwort eingibt und das Formular absendet, wird er authentifiziert. Wenn die Authentifizierung erfolgreich ist, wird die login Methode von django.contrib.auth genannt wird. login prüft, ob die aktuelle Sitzung eine Benutzer-ID enthält; wenn ja, und die ID mit der ID des angemeldeten Benutzers übereinstimmt, SessionStore.cycle_key wird aufgerufen, um einen neuen Sitzungsschlüssel zu erstellen, wobei die Sitzungsdaten erhalten bleiben. Andernfalls, SessionStore.flush aufgerufen wird, um alle Daten zu löschen und eine neue Sitzung zu erstellen. Diese beiden Methoden sollten die vorherige Sitzung (für den anonymen Benutzer) löschen und die SessionStore.create um eine neue Sitzung zu erstellen.
  6. Zu diesem Zeitpunkt ist der Benutzer authentifiziert und hat eine neue Sitzung. Seine ID wird in der Sitzung gespeichert, zusammen mit dem Backend, das zur Authentifizierung verwendet wurde. Die Sitzungs-Middleware speichert diese Daten in der Datenbank und speichert die neue Sitzungs-ID in settings.SESSION_COOKIE_NAME .

Das große Problem bei der bisherigen Lösung ist also, dass zu dem Zeitpunkt, an dem create aufgerufen wird (Schritt 5.), ist die ID der vorherigen Sitzung längst verschwunden. Da andere haben darauf hingewiesen Dies geschieht, weil der Browser den Sitzungs-Cookie nach dessen Ablauf stillschweigend löscht.

Aufbauend auf Vorschlag von Alex Gaynor Ich glaube, ich habe einen anderen Ansatz gefunden, der genau das zu tun scheint, was Sie wollen, auch wenn er noch ein wenig holprig ist. Grundsätzlich verwende ich einen zweiten langlebigen "Audit"-Cookie, um die Sitzungs-ID zu spiegeln, und einige Middleware, um das Vorhandensein dieses Cookies zu überprüfen. Für jede Anfrage:

  • wenn weder das Audit-Cookie noch das Sitzungs-Cookie existieren, handelt es sich wahrscheinlich um einen neuen Benutzer
  • Wenn das Audit-Cookie existiert, das Sitzungs-Cookie aber nicht, handelt es sich wahrscheinlich um einen Benutzer, dessen Sitzung gerade abgelaufen ist.
  • wenn beide Cookies existieren und den gleichen Wert haben, handelt es sich um eine aktive Sitzung

Hier ist der bisherige Code:

sessionaudit.middleware.py :

from django.conf import settings
from django.db.models import signals
from django.utils.http import cookie_date
import time

session_expired = signals.Signal(providing_args=['previous_session_key'])

AUDIT_COOKIE_NAME = 'sessionaudit'

class SessionAuditMiddleware(object):
    def process_request(self, request):
        # The 'print' statements are helpful if you're using the development server
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
        audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
        if audit_cookie is None and session_key is None:
            print "** Got new user **"
        elif audit_cookie and session_key is None:
            print "** User session expired, Session ID: %s **" % audit_cookie
            session_expired.send(self.__class__, previous_session_key=audit_cookie)
        elif audit_cookie == session_key:
            print "** User session active, Session ID: %s **" % audit_cookie

    def process_response(self, request, response):
        if request.session.session_key:
            audit_cookie = request.COOKIES.get(AUDIT_COOKIE_NAME, None)
            if audit_cookie != request.session.session_key:
                # New Session ID - update audit cookie:
                max_age = 60 * 60 * 24 * 365  # 1 year
                expires_time = time.time() + max_age
                expires = cookie_date(expires_time)
                response.set_cookie(
                    AUDIT_COOKIE_NAME,
                    request.session.session_key,
                    max_age=max_age,
                    expires=expires,
                    domain=settings.SESSION_COOKIE_DOMAIN,
                    path=settings.SESSION_COOKIE_PATH,
                    secure=settings.SESSION_COOKIE_SECURE or None
                )
        return response

audit.models.py :

from django.contrib.sessions.models import Session
from sessionaudit.middleware import session_expired

def audit_session_expire(sender, **kwargs):
    try:
        prev_session = Session.objects.get(session_key=kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data.get('_auth_user_id')
    except Session.DoesNotExist:
        pass

session_expired.connect(audit_session_expire)

einstellungen.py :

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'sessionaudit.middleware.SessionAuditMiddleware',
    ...
)

INSTALLED_APPS = (
    ...
    'django.contrib.sessions',
    'audit',
    ...
)

Wenn Sie dies verwenden, sollten Sie eine benutzerdefinierte Abmeldeansicht implementieren, die das Audit-Cookie ausdrücklich löscht, wenn sich der Benutzer abmeldet. Ich würde auch vorschlagen, die django signed-cookies Middleware zu verwenden (aber das tun Sie wahrscheinlich schon, oder?)

OLD:

Ich denke, Sie sollten in der Lage sein, dies mit einem benutzerdefinierten Session-Backend zu tun. Hier ist einige (ungetestet) Beispielcode:

from django.contrib.sessions.backends.db import SessionStore as DBStore
from django.db.models import signals

session_created = signals.Signal(providing_args=['previous_session_key', 'new_session_key'])

class SessionStore(DBStore):
    """
    Override the default database session store.

    The `create` method is called by the framework to:
    * Create a new session, if we have a new user
    * Generate a new session, if the current user's session has expired

    What we want to do is override this method, so we can send a signal
    whenever it is called.
    """

    def create(self):
        # Save the current session ID:
        prev_session_id = self.session_key
        # Call the superclass 'create' to create a new session:
        super(SessionStore, self).create()
        # We should have a new session - raise 'session_created' signal:
        session_created.send(self.__class__, previous_session_key=prev_session_id, new_session_key=self.session_key)

Speichern Sie den obigen Code als "customdb.py" und fügen Sie ihn zu Ihrem Django-Projekt hinzu. Setzen oder ersetzen Sie in Ihrer settings.py "SESSION_ENGINE" durch den Pfad zur obigen Datei, z. B.:

SESSION_ENGINE = 'yourproject.customdb'

Dann in Ihrem Middleware, oder models.py einen Handler für das Signal "session_created" bereitstellen, etwa so:

from django.contrib.sessions.models import Session
from yourproject.customdb import session_created

def audit_session_expire(sender, **kwargs):
    # remember that 'previous_session_key' can be None if we have a new user
    try:
        prev_session = Session.objects.get(kwargs['previous_session_key'])
        prev_session_data = prev_session.get_decoded()
        user_id = prev_session_data['_auth_user_id']
        # do something with the user_id
    except Session.DoesNotExist:
        # new user; do something else...

session_created.connect(audit_session_expire)

Vergessen Sie nicht, die App, die die models.py sur INSTALLED_APPS .

0 Stimmen

Ich bin immer noch verwirrt. Wo muss ich den Empfänger für audit_session_expire() registrieren?

0 Stimmen

audit_session_expire ist der Handler für die benutzerdefinierte session_created signalisieren. Ich habe die Antwort aktualisiert, um zu zeigen, wie es registriert wird.

0 Stimmen

Ich habe Ihre Anweisungen befolgt und sehe nie, dass das Signal die Methode "audit_session_expire()" aufruft. Ich habe sie in meine Datei models.py (in der Anwendung "audit") aufgenommen und die INSTALLED_APPS aktualisiert. Selbst wenn es funktionieren würde, würde dieser Code nicht ausgelöst werden, wenn der Benutzer auf "Logout" klickt?

0voto

Martin Punkte 5651

Ich weiß nicht, über Django, aber können Sie, erstellen Sie einfach einen nicht-persistenten Cookie, der die letzte Zugriffszeit auf eine Seite auf Ihrer Website speichert (Sie aktualisieren Sie das Cookie auf jeder Seite laden)

Dann können Sie auf Ihrer Anmeldeseite prüfen, ob Ihr Benutzer zwar Ihr Cookie, aber keine Sitzung hat. Dann wissen Sie, dass die Sitzung des Benutzers wahrscheinlich abgelaufen ist. Da Sie den Zeitpunkt des letzten Zugriffs auf eine Seite Ihrer Website kennen, können Sie anhand der Dauer der Sitzung auch berechnen, ob diese abgelaufen ist.

0 Stimmen

Ich bin ein asp.net-Programmierer, und diese Art von Problemen passieren auch. (gut, es ist Web-Entwicklung, so dass es ähnlich ist) und dies ist, wie ich versuchen würde, dieses Problem in asp.net zu lösen, also schlage ich diese Antwort.

0voto

stormlifter Punkte 3513

SESSION_COOKIE_AGE = 1500 # 25 Minuten

Geben Sie dies in Ihren Einstellungen ein, und die Sitzung sollte damit beendet sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X