web-dev-qa-db-fra.com

Comment expirer la session en raison de l'inactivité dans Django?

Notre application Django a les exigences de gestion de session suivantes.

  1. Les sessions expirent lorsque l'utilisateur ferme le navigateur.
  2. Les sessions expirent après une période d'inactivité.
  3. Détectez quand une session expire en raison de l'inactivité et affichez le message approprié à l'utilisateur.
  4. Avertir les utilisateurs de l'expiration imminente d'une session quelques minutes avant la fin de la période d'inactivité. Parallèlement à l'avertissement, offrez aux utilisateurs la possibilité de prolonger leur session.
  5. Si l'utilisateur travaille sur une longue activité commerciale dans l'application qui n'implique pas l'envoi de demandes au serveur, la session ne doit pas expirer.

Après avoir lu la documentation, Django code et quelques articles de blog liés à cela, j'ai trouvé l'approche d'implémentation suivante.

Exigence 1
Cette exigence est facilement implémentée en définissant SESSION_EXPIRE_AT_BROWSER_CLOSE sur True.

Exigence 2
J'ai vu quelques recommandations d'utiliser SESSION_COOKIE_AGE pour définir la période d'expiration de la session. Mais cette méthode présente les problèmes suivants.

  • La session expire toujours à la fin de la SESSION_COOKIE_AGE même si l'utilisateur utilise activement l'application. (Cela peut être évité en définissant l'expiration de la session sur SESSION_COOKIE_AGE sur chaque demande à l'aide d'un middleware personnalisé ou en enregistrant la session sur chaque demande en définissant SESSION_SAVE_EVERY_REQUEST sur true. Mais le problème suivant est inévitable en raison de l'utilisation de SESSION_COOKIE_AGE.)

  • En raison du fonctionnement des cookies, SESSION_EXPIRE_AT_BROWSER_CLOSE et SESSION_COOKIE_AGE s'excluent mutuellement, c'est-à-dire que le cookie expire à la fermeture du navigateur ou à l'heure d'expiration spécifiée. Si SESSION_COOKIE_AGE est utilisé et que l'utilisateur ferme le navigateur avant l'expiration du cookie, le cookie est conservé et la réouverture du navigateur permettra à l'utilisateur (ou à toute autre personne) d'accéder au système sans être réauthentifié.

  • Django s'appuie uniquement sur le cookie présent pour déterminer si la session est active. Il ne vérifie pas la date d'expiration de la session enregistrée avec la session.

La méthode suivante peut être utilisée pour implémenter cette exigence et contourner les problèmes mentionnés ci-dessus.

  • Ne définissez pas SESSION_COOKIE_AGE.
  • Définissez la date d'expiration de la session sur "heure actuelle + période d'inactivité" à chaque demande.
  • Remplacez process_request dans SessionMiddleware et vérifiez l'expiration de la session. Jeter la session si elle a expiré.

exigence
Lorsque nous détectons que la session a expiré (dans le SessionMiddleware personnalisé ci-dessus), définissez un attribut sur la demande pour indiquer l'expiration de la session. Cet attribut peut être utilisé pour afficher un message approprié à l'utilisateur.

Exigence 4
Utilisez JavaScript pour détecter l'inactivité de l'utilisateur, fournissez l'avertissement et également une option pour prolonger la session. Si l'utilisateur souhaite prolonger, envoyez une impulsion de maintien en vie au serveur pour prolonger la session.

exigence 5
Utilisez JavaScript pour détecter l'activité des utilisateurs (pendant les opérations de longue durée) et envoyer des impulsions de maintien en vie au serveur pour empêcher l'expiration de la session.


L'approche d'implémentation ci-dessus semble très élaborée et je me demandais s'il pourrait y avoir une méthode plus simple (en particulier pour l'exigence 2).

Toutes les idées seront très appréciées.

84
Akbar ibrahim

Voici une idée ... Expirer la session sur le navigateur fermer avec le SESSION_EXPIRE_AT_BROWSER_CLOSE réglage. Ensuite, définissez un horodatage dans la session sur chaque demande comme ça.

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

et ajoutez un middleware pour détecter si la session a expiré. quelque chose comme ça devrait gérer l'ensemble du processus ...

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

Ensuite, il vous suffit de faire des URL et des vues pour renvoyer les données pertinentes aux appels ajax concernant l'expiration de la session.

lorsque l'utilisateur choisit de "renouveler" la session, pour ainsi dire, tout ce que vous avez à faire est de définir requeset.session['last_activity'] à l'heure actuelle à nouveau

Évidemment, ce code n'est qu'un début ... mais il devrait vous mettre sur la bonne voie

41
Jiaaro

Django-session-security fait exactement cela ...

... avec une exigence supplémentaire: si le serveur ne répond pas ou si un attaquant a déconnecté la connexion Internet: elle doit quand même expirer.

Disclamer: Je maintiens cette application. Mais je regarde ce fil depuis très, très longtemps :)

26
jpic

Je suis juste assez nouveau pour utiliser Django.

Je voulais que la session expire si l'utilisateur connecté ferme le navigateur ou est inactif (délai d'inactivité) pendant un certain temps. Lorsque je l'ai cherché sur Google, cette question SOF est apparue en premier. Grâce à Nice answer, j'ai recherché des ressources pour comprendre le fonctionnement des middlewares pendant le cycle de requête/réponse dans Django. Ce fut très utile.

J'étais sur le point d'appliquer un middleware personnalisé dans mon code après la première réponse ici. Mais j'étais encore un peu méfiant parce que la meilleure réponse ici a été modifiée en 2011. J'ai pris plus de temps pour rechercher un peu à partir des résultats de recherche récents et j'ai trouvé un moyen simple.

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

Je n'ai pas vérifié d'autres navigateurs mais le chrome. 1. Une session a expiré lorsque j'ai fermé un navigateur même si SESSION_COOKIE_AGE était défini. 2. Seulement lorsque j'ai été inactif pendant plus de 10 secondes, une session a expiré. Merci à SESSION_SAVE_EVERY_REQUEST, chaque fois que vous recevez une nouvelle demande, il enregistre la session et met à jour le délai d'expiration

Pour modifier ce comportement par défaut, définissez le paramètre SESSION_SAVE_EVERY_REQUEST sur True. Lorsqu'il est défini sur True, Django enregistrera la session dans la base de données à chaque requête.

Notez que le cookie de session n'est envoyé que lorsqu'une session a été créée ou modifiée. Si SESSION_SAVE_EVERY_REQUEST a la valeur True, le cookie de session sera envoyé à chaque demande.

De même, la partie expirée d'un cookie de session est mise à jour chaque fois que le cookie de session est envoyé.

manuel Django 1.1

Je laisse juste la réponse pour que certaines personnes qui sont une sorte de nouveau dans Django comme moi ne passent pas beaucoup de temps à trouver une solution comme je l'ai fait.

25
Jayground

Un moyen facile de satisfaire votre deuxième exigence serait de définir la valeur SESSION_COOKIE_AGE dans settings.py sur une quantité appropriée de secondes. Par exemple:

SESSION_COOKIE_AGE = 600      #10 minutes.

Cependant, ce faisant, la session expirera après 10 minutes, que l'utilisateur présente ou non une activité. Pour résoudre ce problème, le délai d'expiration peut être automatiquement renouvelé (pour 10 minutes supplémentaires) à chaque fois que l'utilisateur effectue un type de demande avec la phrase suivante:

request.session.set_expiry(request.session.get_expiry_age())
10
Fernando Martin

Dans la première demande, vous pouvez définir l'expiration de la session comme

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

Et lorsque vous utilisez la clé d'accès et le jeton,

try:
    key = self.request.session['access_key']
except KeyError:
    age = self.request.session.get_expiry_age()
    if age > set_age:
        #redirect to login page
3
tilaprimera

vous pouvez également utiliser débordement de pile intégré dans les fonctions

SESSION_SAVE_EVERY_REQUEST = True
3
mexekanez