Suivi de l'expiration de la session dans le navigateur

Donc, il y a cette application Web hétérogène complexe, avec des parties AJAX faites à la fois manuellement et par des frameworks, plusieurs fenêtres contextuelles, etc. Un grand client respectable vous approche avec une exigence d'invalider, de fermer ou de faire une autre activité sur tout le Web fenêtres d'application une fois la session HTTP expirée. J'espère que vous savez comment contrôler l'intervalle de temporisation de la session HTTP, pour une application Web compatible J2EE, cela se fait à partir d'un fichier web.xml (mais dans de nombreux serveurs d'applications, ce n'est pas fait de manière standard). Pour un temps mort de 10 minutes, c'est:

  10  

L'exigence du client n'est pas du tout absurde et est parfaitement logique du point de vue de l'utilisateur final, mais elle peut devenir une douleur terrible pour un développeur parce que: 1. Vous ne pouvez pas simplement démarrer un compte à rebours dans la fenêtre du navigateur chaque fois que la page se charge pour fermer la fenêtre à l'expiration du délai. Cette approche fonctionnait dans un monde non AJAX lorsque chaque interaction navigateur-serveur entraînait le rechargement de la fenêtre du navigateur. 2. Vous ne pouvez pas interroger le serveur pour vérifier si la session HTTP a expiré ou non, car chaque requête sera traitée comme une interaction navigateur-serveur prolongeant la session. Cela conduira à une session qui n'expire jamais. 3. Vous pouvez créer une application Web distincte en tenant compte de la session HTTP de l'application Web principale et en l'intersectant. Mais c'est exagéré,et les chances qu'une telle solution soit acceptée sont extrêmement faibles en raison des problèmes d'intégration susceptibles de survenir. 4. Vous pouvez essayer d'intercepter toutes les interactions navigateur-serveur AJAX avec un code de piratage avancé, et cela vous aidera à gérer votre fenêtre actuelle. Mais cela ne fonctionne pas pour le cas de plusieurs fenêtres ouvertes - vous ne pouvez tout simplement pas communiquer entre les fenêtres du navigateur. La seule façon de parler à une fenêtre ouverte à partir d'une fenêtre principale est d'utiliser la référence JavaScript d'une autre fenêtre, et une fois que la fenêtre principale est rechargée ou dirigée vers un emplacement différent, elle perd toutes les références JavaScript à d'autres fenêtres. 5. L'approche la plus réaliste consiste à envoyer des requêtes JavaScript XMLHTTP périodiques (à partir de chaque fenêtre ouverte) au serveur chaque {intervalle d'inactivité max de session} +10 secondes. Cela finira par fermer toutes les fenêtres,mais peut entraîner la fermeture des fenêtres quelques minutes (voire des heures selon le paramètre de délai d'expiration de la session de l'application Web) après la destruction de la session HTTP, par exemple une fois que l'utilisateur se déconnecte de la fenêtre principale. Plus d'options, vous êtes frustré et vous pensez que c'est le bon moment pour prendre l'arme de votre papa et tirer sur vos camarades de classe à l'école demain. Non, pas encore enfant - il y a encore un moyen de sortir! La sortie n'est pas très simple, mais elle est très élégante. Les cookies nous aideront. On pourrait penser que le délai d'expiration des cookies ferait l'affaire. Malheureusement, comme décrit dansC'est juste le bon moment pour prendre l'arme de ton papa et tirer sur tes camarades de classe demain à l'école. Non, pas encore gamin - il y a encore une issue! La sortie n'est pas très simple, mais elle est très élégante. Les cookies nous aideront. On pourrait penser que le délai d'expiration des cookies ferait l'affaire. Malheureusement, comme décrit dansC'est juste le bon moment pour prendre l'arme de ton papa et tirer sur tes camarades de classe demain à l'école. Non, pas encore enfant - il y a encore un moyen de sortir! La sortie n'est pas très simple, mais elle est très élégante. Les cookies nous aideront. On pourrait penser que le délai d'expiration des cookies ferait l'affaire. Malheureusement, comme décrit dans

ce

article, vous ne pouvez pas vous fier au temps d'expiration des cookies car il est mesuré par un navigateur client, et personne ne peut garantir que l'horloge système du client n'a pas un an de retard. Voici donc le système et la méthode de suivi des délais d'expiration de session HTTP dans les applications Web hétérogènes. A chaque requête d'un navigateur à un serveur, deux cookies sont définis par un filtre de servlet. L'un contient l'heure actuelle du serveur et l'autre l'heure d'expiration de la session. L'heure actuelle du serveur n'est nécessaire que pour calculer un décalage entre le client et le serveur. L'heure d'expiration de la session est ensuite vérifiée périodiquement par rapport à l'heure actuelle du serveur _calculée_ (rappelez-vous le décalage). Chaque fois que _toute_ demande est faite au serveur, le cookie de temps d'expiration est mis à jour, et tout fonctionne simplement. En pratique, cette méthode est réalisée en seulement trois étapes: 1.Créez un filtre de servlet qui filtrerait chaque demande adressée à votre application Web. Configurez-le dans web.xml comme ceci:

  SessionTimeoutCookieFilter some.package.SessionTimeoutCookieFilter   SessionTimeoutCookieFilter /*  

Ne vous inquiétez pas des performances de votre application Web - ce filtre est TRÈS primitif, il ne fait qu'ajouter deux cookies à la réponse:

 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse httpResp = (HttpServletResponse) resp; HttpServletRequest httpReq = (HttpServletRequest) req; long currTime = System.currentTimeMillis(); long expiryTime = currTime + session.getMaxInactiveInterval() * 1000; Cookie cookie = new Cookie("serverTime", "" + currTime); cookie.setPath("/"); httpResp.addCookie(cookie); if (httpReq.getRemoteUser() != null) { cookie = new Cookie("sessionExpiry", "" + expiryTime); } else { cookie = new Cookie("sessionExpiry", "" + currTime); } cookie.setPath("/"); httpResponse.addCookie(cookie); filterChain.doFilter(req, resp); } 

Définir le chemin (vers "/" dans notre cas) est très important. Si vous omettez le paramètre de chemin, le navigateur le calculera automatiquement à partir de l'URL, ce qui entraînera un chaos dans le stockage des cookies de votre navigateur. 2. Nous avons besoin d'un petit JavaScript sur chaque fenêtre pour calculer le décalage entre l'heure du serveur et celle du client. Il ne doit être exécuté qu'une seule fois, mais cela ne ferait pas de mal de l'exécuter à chaque chargement de page:

 function calcOffset() { var serverTime = getCookie('serverTime'); serverTime = serverTime==null ? null : Math.abs(serverTime); var clientTimeOffset = (new Date()).getTime() - serverTime; setCookie('clientTimeOffset', clientTimeOffset); } window.onLoad = function() { calcOffset(); }; 

3. Enfin, nous avons besoin d'une fonction qui vérifierait réellement si la session a expiré. Il doit être exécuté périodiquement, dans notre cas toutes les 10 secondes (ou 10000 millisecondes):

 function checkSession() { var sessionExpiry = Math.abs(getCookie('sessionExpiry')); var timeOffset = Math.abs(getCookie('clientTimeOffset')); var localTime = (new Date()).getTime(); if (localTime - timeOffset > (sessionExpiry+15000)) { // 15 extra seconds to make sure window.close(); } else { setTimeout('checkSession()', 10000); } } 

En effet, la fermeture des fenêtres du navigateur à l'expiration de la session est une pure brutalité, et elle peut et doit être accompagnée d'un message d'avertissement apparaissant comme 1 minute avant la fin de la session. Je suis vraiment intéressé à recevoir votre

rétroaction critique

sur ma méthode.

Cette histoire, "Suivi de l'expiration de session dans le navigateur" a été publiée à l'origine par JavaWorld.