Jak określić, kiedy użytkownik ma limit czasu bezczynności w Django?

Chciałbym przeprowadzić audyt, kiedy użytkownik doświadczył bezczynności w mojej aplikacji Django. Innymi słowy, jeśli data wygaśnięcia sesji pliku cookie użytkownika przekracza SESSION_COOKIE_AGE znalezioną w settings.py, użytkownik zostaje przekierowany na stronę logowania. W takim przypadku powinien również nastąpić audyt. Przez "audyt" mam na myśli zapis powinien być napisany do mojej osoby.tabela kontroli.

Obecnie skonfigurowałem oprogramowanie pośredniczące do przechwytywania tych zdarzeń. Niestety, Django generuje nowe cookie, gdy użytkownik jest przekierowany na stronę logowania, więc nie mogę ustalić, czy użytkownik został przeniesiony na stronę logowania przez bezczynny timeout lub inne zdarzenie.

Z tego co wiem, musiałbym pracować z tabelą "django_session". Jednak rekordy w tej tabeli nie mogą być powiązane z tym użytkownikiem, ponieważ wartość sessionid w pliku cookie jest resetowana, gdy nastąpi przekierowanie.

Zgaduję, że nie jestem pierwszy, który napotyka ten dylemat. Czy ktoś ma wgląd w to, jak aby rozwiązać problem?

Author: kiamlaluno, 2009-03-13

3 answers

Aktualizacja:

Po kilku testach zdaję sobie sprawę, że poniższy kod nie odpowiada na twoje pytanie. Mimo, że działa, a funkcja obsługi sygnału jest wywoływana, prev_session_data jeśli istnieje, nie będzie zawierać żadnych użytecznych informacji.

Po pierwsze, wgląd w ramy sesji:

  1. gdy nowy użytkownik żąda adresu URL aplikacji, generowana jest dla niego nowa sesja - w tym momencie nadal są anonimowi (request.user jest instancją AnonymousUser).
  2. jeśli oni poproś o widok, który wymaga uwierzytelnienia, zostaną one przekierowane do widoku logowania.
  3. gdy wymagany jest widok login, ustawia wartość testową w sesji użytkownika (SessionStore._session); automatycznie Ustawia flagi accessed i modified na bieżącej sesji.
  4. podczas fazy odpowiedzi powyższego żądania, SessionMiddleware zapisuje bieżącą sesję, skutecznie tworząc nową instancję Session w tabeli django_session (Jeśli używasz domyślnych sesji wspieranych przez bazę danych, dostarczonych przez django.contrib.sessions.backends.db). Na identyfikator nowej sesji jest zapisywany w pliku cookie settings.SESSION_COOKIE_NAME.
  5. gdy użytkownik wpisuje swoją nazwę użytkownika i hasło i przesyła Formularz, są one uwierzytelniane. Jeśli uwierzytelnienie powiedzie się, zostanie wywołana metoda login z django.contrib.auth. login sprawdza, czy bieżąca sesja zawiera identyfikator użytkownika; jeśli tak, a identyfikator jest taki sam jak identyfikator zalogowanego użytkownika, SessionStore.cycle_key jest wywoływany w celu utworzenia nowego klucza sesji, zachowując dane sesji. W przeciwnym razie wywołane jest SessionStore.flush, aby usunąć wszystkie dane i wygenerować nowa sesja. Obie te metody powinny usunąć poprzednią sesję (dla anonimowego użytkownika) i wywołać SessionStore.create, aby utworzyć nową sesję.
  6. w tym momencie użytkownik jest uwierzytelniony i ma nową sesję. Ich identyfikator jest zapisywany w sesji, wraz z backendem używanym do ich uwierzytelniania. Oprogramowanie pośredniczące sesji zapisuje te dane do bazy danych i zapisuje ich nowy identyfikator sesji w settings.SESSION_COOKIE_NAME.

Więc widzisz, duży problem z poprzednim rozwiązaniem jest do czasu create zostaje wywołana (Etap 5.), ID poprzedniej sesji już dawno minęło. Jak zauważyli inni , dzieje się tak, ponieważ po wygaśnięciu pliku cookie sesji jest on po cichu usuwany przez przeglądarkę.

Bazując na sugestii Alexa Gaynora, myślę, że wymyśliłem inne podejście, które wydaje się robić to, o co prosisz, choć nadal jest trochę szorstkie. Zasadniczo używam drugiego długowiecznego pliku cookie" audit", aby odzwierciedlić identyfikator sesji i niektóre oprogramowanie pośredniczące do sprawdzenia za obecność tego ciastka. Na każde żądanie:
    Jeśli nie istnieje plik cookie audytu ani plik cookie sesji, prawdopodobnie jest to nowy użytkownik]} Jeśli plik cookie audytu istnieje, ale plik cookie sesji nie istnieje, prawdopodobnie jest to Użytkownik, którego sesja właśnie wygasła]} Jeśli oba pliki cookie istnieją i mają tę samą wartość, jest to aktywna sesja

Oto kod więc daleko:

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)

settings.py :

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

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

Jeśli tego używasz, powinieneś zaimplementować niestandardowy widok wylogowania, który wyraźnie usuwa plik cookie audytu po wylogowaniu użytkownika. Sugerowałbym również użycie oprogramowania pośredniczącego Django signed-cookies (ale prawdopodobnie już to robisz, prawda?)

Stary:

Myślę, że powinieneś być w stanie to zrobić za pomocą custom session backend. Oto niektóre (nieprzetestowane) przykładowy kod:

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)

Zapisz powyższy kod jako "customdb.py' i dodaj to do swojego projektu django. W Twoim settings.py, ustawić lub zastąpić 'SESSION_ENGINE' ścieżką do powyższego pliku, np.:

SESSION_ENGINE = 'yourproject.customdb'

Następnie w Twoim middleware, lub models.py, dostarcza obsługę sygnału' session_created ' w następujący sposób:

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)

Nie zapomnij dołączyć aplikacji zawierającej models.py w INSTALLED_APPS.

 9
Author: elo80ka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-18 08:32:24

SESSION_COOKIE_AGE = 1500 # 25 minut

Umieść to w swoich ustawieniach i to powinno się tym zająć i zakończyć sesję.

 1
Author: stormlifter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-09 18:42:44

Nie wiem jak Django, ale czy możesz po prostu utworzyć nietrwały plik cookie, który przechowuje ostatni czas dostępu do strony w Twojej witrynie (aktualizujesz plik cookie przy każdym załadowaniu strony)

Następnie, na stronie logowania, możesz sprawdzić, czy twój użytkownik ma plik cookie, ale nie ma sesji, to wiesz, że sesja użytkownika prawdopodobnie wygasła. Ponieważ masz czas ostatniego dostępu do strony w witrynie, możesz również obliczyć, na podstawie czasu trwania sesji, jeśli została ona przekroczona Wynocha.

 0
Author: Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-13 22:56:01