112 votes

Comment expirer une session pour cause d'inactivité dans Django ?

Notre application Django a les exigences suivantes en matière de gestion des sessions.

  1. Les sessions expirent lorsque l'utilisateur ferme son navigateur.
  2. Les sessions expirent après une période d'inactivité.
  3. Détecter l'expiration d'une session pour cause d'inactivité et afficher un message approprié à l'utilisateur.
  4. Prévenez les utilisateurs de l'expiration imminente de leur session quelques minutes avant la fin de la période d'inactivité. En même temps que l'avertissement, offrez aux utilisateurs la possibilité de prolonger leur session.
  5. Si l'utilisateur travaille sur une longue activité professionnelle dans l'application qui n'implique pas l'envoi de requêtes au serveur, la session ne doit pas expirer.

Après avoir lu la documentation, le code de Django et quelques articles de blog à ce sujet, j'ai trouvé l'approche de mise en œuvre suivante.

Exigence 1
Cette exigence est facilement mise en œuvre en donnant à SESSION_EXPIRE_AT_BROWSER_CLOSE la valeur 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 du SESSION_COOKIE_AGE, même si l'utilisateur utilise activement l'application. (On peut éviter ce problème en fixant l'expiration de la session à SESSION_COOKIE_AGE à chaque demande à l'aide d'un intergiciel personnalisé ou en sauvegardant la session à chaque demande en fixant SESSION_SAVE_EVERY_REQUEST à 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 soit à la fermeture du navigateur, soit à 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 se fie uniquement à la présence du cookie pour déterminer si la session est active. Il ne vérifie pas la date d'expiration de la session stockée avec celle-ci.

La méthode suivante pourrait être utilisée pour mettre en œuvre cette exigence et contourner les problèmes mentionnés ci-dessus.

  • Ne pas définir SESSION_COOKIE_AGE.
  • Définissez la date d'expiration de la session comme étant "l'heure actuelle + la période d'inactivité" à chaque demande.
  • Remplacer process_request dans SessionMiddleware et vérifier l'expiration de la session. Abandonnez la session si elle a expiré.

Exigence 3
Lorsque nous détectons que la session a expiré (dans le SessionMiddleware personnalisé ci-dessus), nous définissons 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, lui adresser un avertissement et lui proposer une option de prolongation de la session. Si l'utilisateur souhaite prolonger la session, envoyez une impulsion de maintien en vie au serveur pour prolonger la session.

Exigence 5
Utilisez JavaScript pour détecter l'activité de l'utilisateur (pendant les longues opérations commerciales) et envoyez des impulsions de maintien en vie au serveur pour empêcher l'expiration de la session.


L'approche de mise en œuvre ci-dessus semble très élaborée et je me demandais s'il n'y avait pas une méthode plus simple (en particulier pour l'exigence 2).

Tout commentaire sera très apprécié.

3 votes

+1 pour avoir fourni une solution détaillée

0 votes

Il existe un intergiciel qui peut faire ce dont vous avez besoin. sur github y sur pypi

1 votes

"En raison du mode de fonctionnement des cookies, SESSION_EXPIRE_AT_BROWSER_CLOSE et SESSION_COOKIE_AGE s'excluent mutuellement, c'est-à-dire que le cookie expire soit à la fermeture du navigateur, soit à 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é." Corrigez-moi si je me trompe, mais cela ne semble plus être vrai dans les nouvelles versions de Django ? (1.5+ au moins)

51voto

Jayground Points 779

Je suis juste assez nouveau dans l'utilisation de Django.

Je voulais faire en sorte que la session expire si l'utilisateur connecté ferme le navigateur ou est en inactivité (inactivity timeout) pendant un certain temps. Lorsque j'ai fait une recherche sur Google, la question du FOS est apparue en premier. Grâce à la bonne réponse, j'ai cherché des ressources pour comprendre comment les intergiciels fonctionnent pendant le cycle demande/réponse dans Django. C'était très utile.

J'étais sur le point d'appliquer un middleware personnalisé dans mon code en suivant la réponse du top ici. Mais j'étais encore un peu méfiant car la meilleure réponse ici a été éditée en 2011. J'ai pris plus de temps pour chercher un peu dans les 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é les autres navigateurs, sauf Chrome.

  1. Une session a expiré lorsque j'ai fermé un navigateur, même si SESSION_COOKIE_AGE a été défini.
  2. Seulement quand j'étais inactif pendant plus de 10 secondes, une session a expiré. Grâce à SESSION_SAVE_EVERY_REQUEST, chaque fois que vous faites une nouvelle demande, il sauvegarde 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 a la valeur True, Django enregistre 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 est True, le cookie de session sera envoyé à chaque demande.

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

manuel django 1.10

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

47voto

Jiaaro Points 14379

Voici une idée... Expirez la session à la fermeture du navigateur avec l'option SESSION_EXPIRE_AT_BROWSER_CLOSE réglage. Ensuite, définissez un horodatage dans la session à chaque demande comme suit.

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

et ajouter un middleware pour détecter si la session est expirée. 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

Il suffit ensuite de créer des urls et des vues pour renvoyer des 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 devez 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.

0 votes

Je suis juste sceptique ici, mais je ne pense pas que la if not request.is_ajax() est totalement sûr. Quelqu'un qui s'empare de la session avant son expiration ne peut-il pas usurper/envoyer un appel ajax et maintenir la session ?

2 votes

@notbad.jpeg : en général, l'"activité" est facilement falsifiable. Quelqu'un qui s'empare de la session et continue à envoyer des requêtes est simplement actif.

0 votes

C'est une excellente réponse. L'intergiciel est un outil très sous-utilisé dans le développement de Django.

27voto

jpic Points 17307

django-session-security fait exactement ça...

... avec une exigence supplémentaire : si le serveur ne répond pas ou si un attaquant a déconnecté la connexion internet : il doit expirer de toute façon.

Clause de non-responsabilité : J'assure la maintenance de cette application. Mais je regarde ce fil de discussion depuis très, très longtemps :)

1 votes

Application cool - bien conçue et bien construite. code propre et agréable... merci.

0 votes

Si l'utilisateur ferme le navigateur ou l'onglet (sans se déconnecter) lorsqu'il part, le système oblige-t-il quand même l'utilisateur à se déconnecter ? Le système gère-t-il cette condition ?

0 votes

Cela serait géré par l'expiration du cookie de session pure-http, n'est-ce pas ?

16voto

Fernando Martin Points 394

Une façon simple de satisfaire votre deuxième exigence serait de définir la valeur SESSION_COOKIE_AGE dans settings.py à une quantité appropriée de secondes. Par exemple :

SESSION_COOKIE_AGE = 600      #10 minutes.

Cependant, en ne faisant que cela, la session expirera au bout de 10 minutes, que l'utilisateur fasse preuve ou non d'une certaine 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 une demande quelconque avec la phrase suivante :

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

2 votes

SESSION_COOKIE_AGE = 600 Cela prolongera l'âge des sessions à chaque nouvelle demande ou rafraîchissement de page.

2 votes

Je confirme que le fait de mettre SESSION_COOKIE_AGE est suffisante et que toute requête (envoyant le cookie de session) rafraîchira automatiquement l'expiration du cookie de session.

5voto

mexekanez Points 1

Vous pouvez également utiliser fonctions intégrées dans le stackoverflow

SESSION_SAVE_EVERY_REQUEST = True

1 votes

Totalement sans rapport - c'est pour forcer une session (et non "rafraîchissement du cookie de session") à chaque demande sans vérifier si la session a été modifiée.

0 votes

@brunodesthuilliers En fait, ce n'est pas sans rapport. La sauvegarde de la session met également à jour le délai d'expiration de la session.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X