Come far scadere la sessione a causa di inattività in Django?


93

La nostra applicazione Django ha i seguenti requisiti di gestione delle sessioni.

  1. Le sessioni scadono quando l'utente chiude il browser.
  2. Le sessioni scadono dopo un periodo di inattività.
  3. Rileva quando una sessione scade a causa di inattività e visualizza il messaggio appropriato all'utente.
  4. Avvisa gli utenti dell'imminente scadenza della sessione pochi minuti prima della fine del periodo di inattività. Insieme all'avviso, fornire agli utenti un'opzione per estendere la propria sessione.
  5. Se l'utente sta lavorando a una lunga attività aziendale all'interno dell'app che non comporta l'invio di richieste al server, la sessione non deve scadere.

Dopo aver letto la documentazione, il codice Django e alcuni post del blog relativi a questo, ho trovato il seguente approccio di implementazione.

Requisito 1
Questo requisito può essere facilmente implementato impostando SESSION_EXPIRE_AT_BROWSER_CLOSE su True.

Requisito 2
Ho visto alcuni consigli per utilizzare SESSION_COOKIE_AGE per impostare il periodo di scadenza della sessione. Ma questo metodo presenta i seguenti problemi.

  • La sessione scade sempre alla fine della SESSION_COOKIE_AGE anche se l'utente sta utilizzando attivamente l'applicazione. (Questo può essere evitato impostando la scadenza della sessione su SESSION_COOKIE_AGE su ogni richiesta utilizzando un middleware personalizzato o salvando la sessione su ogni richiesta impostando SESSION_SAVE_EVERY_REQUEST su true. Ma il problema successivo è inevitabile a causa dell'uso di SESSION_COOKIE_AGE.)

  • A causa del modo in cui funzionano i cookie, SESSION_EXPIRE_AT_BROWSER_CLOSE e SESSION_COOKIE_AGE si escludono a vicenda, ovvero il cookie scade alla chiusura del browser o all'ora di scadenza specificata. Se viene utilizzato SESSION_COOKIE_AGE e l'utente chiude il browser prima della scadenza del cookie, il cookie viene conservato e la riapertura del browser consentirà all'utente (oa chiunque altro) di accedere al sistema senza essere nuovamente autenticato.

  • Django si basa solo sulla presenza del cookie per determinare se la sessione è attiva. Non controlla la data di scadenza della sessione memorizzata con la sessione.

Il metodo seguente può essere utilizzato per implementare questo requisito e per risolvere i problemi sopra menzionati.

  • Non impostare SESSION_COOKIE_AGE.
  • Imposta la data di scadenza della sessione su "ora corrente + periodo di inattività" su ogni richiesta.
  • Sostituisci process_request in SessionMiddleware e controlla la scadenza della sessione. Elimina la sessione se è scaduta.

Requisito 3
Quando rileviamo che la sessione è scaduta (nel SessionMiddleware personalizzato sopra), impostare un attributo sulla richiesta per indicare la scadenza della sessione. Questo attributo può essere utilizzato per visualizzare un messaggio appropriato all'utente.

Requisito 4
Utilizzare JavaScript per rilevare l'inattività dell'utente, fornire l'avviso e anche un'opzione per estendere la sessione. Se l'utente desidera estendere, inviare un impulso di keepalive al server per estendere la sessione.

Requisito 5
Utilizzare JavaScript per rilevare l'attività dell'utente (durante le lunghe operazioni aziendali) e inviare impulsi di mantenimento al server per impedire la scadenza della sessione.


L'approccio di implementazione di cui sopra sembra molto elaborato e mi chiedevo se potesse esserci un metodo più semplice (specialmente per il Requisito 2).

Eventuali approfondimenti saranno molto apprezzati.


3
+1 per fornire una soluzione dettagliata
Don

C'è un middleware che può fare quello che ti serve. su GitHub e Pypi
gbutler

1
"A causa del modo in cui funzionano i cookie, SESSION_EXPIRE_AT_BROWSER_CLOSE e SESSION_COOKIE_AGE si escludono a vicenda, ovvero il cookie scade alla chiusura del browser o all'ora di scadenza specificata. Se viene utilizzato SESSION_COOKIE_AGE e l'utente chiude il browser prima della scadenza del cookie, il cookie viene conservato e riaperto il browser consentirà all'utente (oa chiunque altro) di accedere al sistema senza essere nuovamente autenticato. " Correggimi se sbaglio, ma questo non sembra più essere vero nelle nuove versioni di Django? (1.5+ almeno)
Botond Béres

1
"Django si basa solo sul cookie presente per determinare se la sessione è attiva. Non controlla la data di scadenza della sessione memorizzata con la sessione." Questo non è più vero .
knaperek

Risposte:


44

Ecco un'idea ... Fai scadere la sessione alla chiusura del browser con l' SESSION_EXPIRE_AT_BROWSER_CLOSEimpostazione. Quindi imposta un timestamp nella sessione su ogni richiesta in questo modo.

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

e aggiungi un middleware per rilevare se la sessione è scaduta. qualcosa del genere dovrebbe gestire l'intero processo ...

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

Quindi devi solo creare alcuni URL e visualizzazioni per restituire dati rilevanti alle chiamate ajax riguardanti la scadenza della sessione.

quando l'utente sceglie di "rinnovare" la sessione, per così dire, tutto ciò che devi fare è impostare requeset.session['last_activity']nuovamente l'ora corrente

Ovviamente questo codice è solo l'inizio ... ma dovrebbe portarti sulla strada giusta


Sono solo scettico qui, ma non credo che if not request.is_ajax()sia completamente sicuro. Qualcuno che ottiene una sospensione della sessione prima della scadenza falsifica / invia una chiamata ajax e continua la sessione?
notbad.jpeg

2
@ notbad.jpeg: in generale "attività" è facilmente falsificabile. Qualcuno che si impossessa della sessione e continua a inviare richieste è solo attivo.
RemcoGerlich

Questa è un'ottima risposta. Il middleware è uno strumento molto sottoutilizzato nello sviluppo di Django.
Jamie Counsell

30

Sono solo abbastanza nuovo nell'usare Django.

Volevo far scadere la sessione se l'utente registrato chiude il browser o è inattivo (timeout di inattività) per un certo periodo di tempo. Quando ho cercato su Google per capire, questa domanda SOF è venuta per prima. Grazie alla bella risposta, ho cercato risorse per capire come funzionano i middleware durante il ciclo di richiesta / risposta in Django. È stato molto utile.

Stavo per applicare middleware personalizzato nel mio codice seguendo la risposta principale qui. Ma ero ancora un po 'sospettoso perché la migliore risposta qui è stata modificata nel 2011. Ho impiegato più tempo per cercare un po' dai risultati di ricerca recenti e ho trovato un modo semplice.

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

Non ho controllato altri browser tranne Chrome. 1. Una sessione è scaduta quando ho chiuso un browser anche se SESSION_COOKIE_AGE è stato impostato. 2. Solo quando sono rimasto inattivo per più di 10 secondi, una sessione è scaduta. Grazie a SESSION_SAVE_EVERY_REQUEST, ogni volta che si verifica una nuova richiesta, salva la sessione e aggiorna il timeout in scadenza

Per modificare questo comportamento predefinito, impostare l'impostazione SESSION_SAVE_EVERY_REQUEST su True. Quando impostato su True, Django salverà la sessione nel database ad ogni singola richiesta.

Notare che il cookie di sessione viene inviato solo quando una sessione è stata creata o modificata. Se SESSION_SAVE_EVERY_REQUEST è True, il cookie di sessione verrà inviato ad ogni richiesta.

Allo stesso modo, la parte in scadenza di un cookie di sessione viene aggiornata ogni volta che viene inviato il cookie di sessione.

manuale django 1.10

Lascio solo la risposta in modo che alcune persone che sono una sorta di nuovo in Django come me non passino molto tempo a trovare una soluzione come ho fatto io.


26

django-session-security fa proprio questo ...

... con un requisito aggiuntivo: se il server non risponde o un utente malintenzionato ha disconnesso la connessione Internet: dovrebbe scadere comunque.

Disclamer: mantengo questa app. Ma ho guardato questo thread per molto, molto tempo :)


1
bella app - ben progettata e ben costruita. codice bello e pulito ... grazie.
nicorellius

Se l'utente chiude il browser o la scheda (senza disconnettersi) quando esce, obbliga comunque a disconnettersi? Gestisce questa condizione?
Mehmet Kagan Kayaalp

Ciò verrebbe gestito dalla scadenza del cookie di sessione http puro, no?
jpic

10

Un modo semplice per soddisfare il tuo secondo requisito sarebbe impostare il valore SESSION_COOKIE_AGE in settings.py su una quantità adeguata di secondi. Per esempio:

SESSION_COOKIE_AGE = 600      #10 minutes.

Tuttavia, solo in questo modo la sessione scadrà dopo 10 minuti indipendentemente dal fatto che l'utente mostri o meno attività. Per affrontare questo problema, il tempo di scadenza può essere rinnovato automaticamente (per altri 10 minuti extra) ogni volta che l'utente esegue qualsiasi tipo di richiesta con la seguente frase:

request.session.set_expiry(request.session.get_expiry_age())

2
SESSION_COOKIE_AGE = 600 Ciò estenderà l'età delle sessioni ad ogni nuova richiesta di pagina o aggiornamento della pagina
Aseem

1
Confermo che SESSION_COOKIE_AGEè sufficiente solo l'impostazione e che qualsiasi richiesta (invio del cookie di sessione) aggiornerà automaticamente la scadenza del cookie di sessione.
bruno desthuilliers


3

Nella prima richiesta è possibile impostare la scadenza della sessione come

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

E quando si utilizzano access_key e token,

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.