Come faccio a determinare quando un utente ha un timeout di inattività in Django?

StackOverflow https://stackoverflow.com/questions/644471

  •  22-07-2019
  •  | 
  •  

Domanda

Vorrei verificare quando un utente ha riscontrato un timeout di inattività nella mia applicazione Django. In altre parole, se la data di scadenza del cookie della sessione dell'utente supera SESSION_COOKIE_AGE trovata in settings.py, l'utente viene reindirizzato alla pagina di accesso. Quando ciò si verifica, dovrebbe anche verificarsi un controllo. Con "audit", intendo un record deve essere scritto nella mia tabella person.audit.

Attualmente, ho configurato alcuni middleware per acquisire questi eventi. Sfortunatamente, Django genera un nuovo cookie quando l'utente viene reindirizzato alla pagina di accesso, quindi non posso determinare se l'utente è stato portato alla pagina di accesso tramite un timeout di inattività o qualche altro evento.

Da quello che posso dire, avrei bisogno di lavorare con la "quotazione_jj_session" tavolo. Tuttavia, i record in questa tabella non possono essere associati a quell'utente perché il valore sessionid nel cookie viene resettato quando si verifica il reindirizzamento.

Suppongo di non essere il primo a incontrare questo dilemma. Qualcuno ha un'idea di come risolvere il problema?

È stato utile?

Soluzione

Aggiornamento:

Dopo un po 'di test, mi rendo conto che il codice qui sotto non risponde alla tua domanda. Anche se funziona e viene chiamato il gestore del segnale, prev_session_data se esiste, non conterrà alcuna informazione utile.

Innanzitutto, uno sguardo all'interno del framework delle sessioni:

  1. Quando un nuovo visitatore richiede un URL dell'applicazione, viene generata una nuova sessione per loro - a questo punto, sono ancora anonimi ( request.user è un'istanza di AnonymousUser).
  2. Se richiedono una vista che richiede autenticazione, vengono reindirizzati alla vista di accesso.
  3. Quando viene richiesta la vista di accesso, imposta un valore di test nella sessione dell'utente ( SessionStore._session ); questo imposta automaticamente i flag accessibili e modificati sulla sessione corrente.
  4. Durante la fase di risposta della richiesta precedente, il SessionMiddleware salva la sessione corrente, creando in modo efficace una nuova istanza Session nella tabella django_session (se stai utilizzando le sessioni predefinite supportate dal database, fornite da django.contrib.sessions.backends.db ). L'id della nuova sessione viene salvato nelle settings.SESSION_COOKIE_NAME cookie.
  5. Quando l'utente digita il nome utente e la password e invia il modulo, viene autenticato. Se l'autenticazione ha esito positivo, viene chiamato il metodo login da django.contrib.auth . login verifica se la sessione corrente contiene un ID utente; in caso affermativo e l'ID è uguale all'ID dell'utente che ha effettuato l'accesso, viene chiamato SessionStore.cycle_key per creare una nuova chiave di sessione, mantenendo i dati della sessione. Altrimenti, viene chiamato SessionStore.flush , per rimuovere tutti i dati e generare una nuova sessione. Entrambi questi metodi dovrebbero eliminare la sessione precedente (per l'utente anonimo) e chiamare SessionStore.create per creare una nuova sessione.
  6. A questo punto, l'utente è autenticato e ha una nuova sessione. Il loro ID viene salvato nella sessione, insieme al back-end utilizzato per autenticarli. Il middleware di sessione salva questi dati nel database e salva il loro nuovo ID sessione in settings.SESSION_COOKIE_NAME .

Quindi, vedete, il grosso problema con la soluzione precedente è quando si chiama create (passaggio 5.), l'ID della sessione precedente è sparito da tempo. Come altri hanno sottolineato , ciò accade perché una volta che il il cookie di sessione scade, viene eliminato silenziosamente dal browser.

Basandosi su Suggerimento di Alex Gaynor , Penso di aver escogitato un altro approccio, che sembra fare quello che mi stai chiedendo, anche se è ancora un po 'agitato attorno ai bordi. Fondamentalmente, utilizzo un secondo "audit" di lunga durata " cookie, per rispecchiare l'ID sessione e alcuni middleware per verificare la presenza di quel cookie. Per qualsiasi richiesta:

  • se non esistono né il cookie di verifica né il cookie di sessione, si tratta probabilmente di un nuovo utente
  • se esiste il cookie di controllo, ma il cookie della sessione no, si tratta probabilmente di un utente la cui sessione è scaduta
  • se esistono entrambi i cookie e hanno lo stesso valore, questa è una sessione attiva

Ecco il codice finora:

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',
    ...
)

Se lo stai utilizzando, devi implementare una vista di disconnessione personalizzata, che elimina esplicitamente il cookie di verifica quando l'utente si disconnette. Inoltre, suggerirei di utilizzare il middleware django firmato-cookies (ma probabilmente lo stai già facendo, vero?)

OLD:

Penso che y

Altri suggerimenti

SESSION_COOKIE_AGE = 1500 # 25 minuti

Mettilo nelle tue impostazioni e questo dovrebbe occuparsene e scadere la sessione.

Non conosco Django, ma puoi semplicemente creare un cookie non persistente, che memorizza l'ultimo tempo di accesso a una pagina del tuo sito (aggiorni il cookie ad ogni caricamento di pagina)

Quindi, nella tua pagina di accesso, puoi verificare se il tuo utente ha i tuoi cookie, ma nessuna sessione, quindi, sai che la sessione dell'utente è probabilmente scaduta. Poiché hai il tempo dell'ultimo accesso a una pagina del tuo sito, puoi anche calcolare, in base alla durata della sessione, se è scaduto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top