Question

Je souhaite vérifier lorsqu'un utilisateur a rencontré un délai d'inactivité dans mon application Django. En d'autres termes, si la date d'expiration du cookie de session de l'utilisateur dépasse la SESSION_COOKIE_AGE trouvée dans settings.py, l'utilisateur est redirigé vers la page de connexion. Lorsque cela se produit, un audit devrait également avoir lieu. Par "audit", je veux dire qu'un enregistrement doit être écrit dans ma table person.audit.

Actuellement, j'ai configuré un middleware pour capturer ces événements. Malheureusement, Django génère un nouveau cookie lorsque l'utilisateur est redirigé vers la page de connexion. Je ne peux donc pas déterminer s'il a été amené sur la page de connexion via un délai d'inactivité ou un autre événement.

D'après ce que je peux dire, il faudrait que je travaille avec le "quot django_session". table. Cependant, les enregistrements de cette table ne peuvent pas être associés à cet utilisateur, car la valeur sessionid du cookie est réinitialisée lorsque la redirection se produit.

Je suppose que je ne suis pas le premier à rencontrer ce dilemme. Quelqu'un a-t-il un aperçu de la façon de résoudre le problème?

Était-ce utile?

La solution

Mise à jour:

Après quelques essais, je me rends compte que le code ci-dessous ne répond pas à votre question. Bien que cela fonctionne et que le gestionnaire de signal soit appelé, prev_session_data s'il existe, ne contiendra aucune information utile.

Tout d'abord, un aperçu du cadre des sessions:

  1. Lorsqu'un nouveau visiteur demande une URL d'application, une nouvelle session lui est générée. À ce stade, il est toujours anonyme ( request.user est une instance de AnonymousUser).
  2. S'ils demandent une vue nécessitant une authentification, ils sont redirigés vers la vue de connexion.
  3. Lorsque la vue de connexion est demandée, elle définit une valeur de test dans la session de l'utilisateur ( SessionStore._session ); cela définit automatiquement les indicateurs consultés et modifiés sur la session en cours.
  4. Au cours de la phase de réponse de la requête ci-dessus, le SessionMiddleware enregistre la session en cours en créant une nouvelle instance Session dans la table django_session . (Si vous utilisez les sessions sauvegardées par base de données par défaut, fournies par django.contrib.sessions.backends.db ). L'identifiant de la nouvelle session est enregistré dans le cookie settings.SESSION_COOKIE_NAME .
  5. Lorsque l'utilisateur tape son nom d'utilisateur et son mot de passe et soumet le formulaire, il est authentifié. Si l'authentification réussit, la méthode login de django.contrib.auth est appelée. login vérifie si la session en cours contient un ID utilisateur; Si tel est le cas et si l'ID est identique à l'ID de l'utilisateur connecté, SessionStore.cycle_key est appelé pour créer une nouvelle clé de session, tout en conservant les données de la session. Sinon, SessionStore.flush est appelé pour supprimer toutes les données et générer une nouvelle session. Ces deux méthodes devraient supprimer la session précédente (pour l'utilisateur anonyme) et appeler SessionStore.create pour créer une nouvelle session.
  6. À ce stade, l'utilisateur est authentifié et a une nouvelle session. Leur identifiant est enregistré dans la session, avec le backend utilisé pour les authentifier. Le middleware de session enregistre ces données dans la base de données, ainsi que leur nouvel identifiant de session dans settings.SESSION_COOKIE_NAME .

Vous voyez donc que le gros problème de la solution précédente est que lorsque create est appelé (étape 5), l'identifiant de la session précédente a disparu depuis longtemps. Comme d'autres l'ont signalé , cela se produit une fois Le cookie de session expire, il est supprimé silencieusement par le navigateur.

Mise à profit de suggestion d'Alex Gaynor , Je pense que j'ai proposé une autre approche, qui semble faire ce que vous demandez, même si cela reste un peu difficile. Fondamentalement, j’utilise un deuxième "audit" de longue durée. cookie, pour refléter l'ID de session, et un middleware pour vérifier la présence de ce cookie. Pour toute demande:

  • si ni le cookie d'audit ni le cookie de session n'existent, il s'agit probablement d'un nouvel utilisateur
  • si le cookie d'audit existe, mais pas le cookie de session, il s'agit probablement d'un utilisateur dont la session vient juste d'arriver à expiration
  • si les deux cookies existent et ont la même valeur, il s'agit d'une session active

Voici le code jusqu'à présent:

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

Si vous utilisez cela, vous devez implémenter une vue de déconnexion personnalisée, qui supprime explicitement le cookie d'audit lorsque l'utilisateur se déconnecte. De plus, je suggérerais d'utiliser le middleware django signé-cookies (mais vous le faites probablement déjà, n'est-ce pas?)

ANCIEN:

je pense que

Autres conseils

SESSION_COOKIE_AGE = 1500 # 25 minutes

Mettez cela dans vos paramètres et cela devrait en prendre soin et faire expirer la session.

Je ne connais pas Django, mais vous pouvez simplement créer un cookie non persistant, qui stocke la dernière heure d'accès à une page de votre site (vous mettez à jour le cookie à chaque chargement de page)

Ensuite, sur votre page de connexion, vous pouvez vérifier si votre utilisateur possède votre cookie, mais pas de session. Vous savez donc que sa session a probablement expiré. Comme vous avez l'heure du dernier accès à une page de votre site, vous pouvez également calculer, en fonction de la durée de la session, si le délai a expiré.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top