Come faccio a determinare quando un utente ha un timeout di inattività in Django?
-
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?
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:
- 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). - Se richiedono una vista che richiede autenticazione, vengono reindirizzati alla vista di accesso.
- Quando viene richiesta la vista di accesso, imposta un valore di test nella sessione dell'utente (
SessionStore._session
); questo imposta automaticamente i flagaccessibili
emodificati
sulla sessione corrente. - Durante la fase di risposta della richiesta precedente, il
SessionMiddleware
salva la sessione corrente, creando in modo efficace una nuova istanzaSession
nella tabelladjango_session
(se stai utilizzando le sessioni predefinite supportate dal database, fornite dadjango.contrib.sessions.backends.db
). L'id della nuova sessione viene salvato nellesettings.SESSION_COOKIE_NAME
cookie. - 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
dadjango.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 chiamatoSessionStore.cycle_key
per creare una nuova chiave di sessione, mantenendo i dati della sessione. Altrimenti, viene chiamatoSessionStore.flush
, per rimuovere tutti i dati e generare una nuova sessione. Entrambi questi metodi dovrebbero eliminare la sessione precedente (per l'utente anonimo) e chiamareSessionStore.create
per creare una nuova sessione. - 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.