Servlets - Gestion des sessions

Décembre 2016

HTTP: un protocole non connecté

Le protocole HTTP est un protocole non connecté (on parle aussi de protocole sans états, en anglais stateless protocol), cela signifie que chaque requête est traitée indépendamment des autres et qu'aucun historique des différentes requêtes n'est conservé. Ainsi le serveur web ne peut pas se "souvenir" de la requête précédente, ce qui est dommageable dans des utilisations telles que le e-commerce, pour lequel le serveur doit mémoriser les achats de l'utilisateur sur les différentes pages.

Il s'agit donc de maintenir la cohésion entre l'utilisateur et la requête, c'est-à-dire :

  • reconnaître les requêtes provenant du même utilisateur
  • associer un profil à l'utilisateur
  • connaître les paramètre de l'application (nombre de produits vendus, ...)


On appelle ce mécanisme de gestion des états le suivi de session (en anglais session tracking).

Les méthodes traditionnelles de suivi de session

Il existe une méthode (pouvant se décliner en plusieurs variantes) permettant d'assurer le suivi de session :
Elle consiste à stocker les informations concernant l'utilisateur sur le serveur, et de les relier à chaque requête grâce à un identifiant (généralement appelé id) présent dans la requête et sur le serveur.

Il existe plusieurs façons standards (utilisées dans tous les types de technologies côté serveur) de passer l'identifiant en paramètre dans la requête :

  • en échangeant des données d'identification du client entre chaque requête
    • en ajoutant à l'URL des variables d'identification
    • en passant en paramètre un champ de formulaire caché
    • en utilisant les cookies
  • en demandant l'identification de l'utilisateur à chaque requête


Les informations concernant l'utilisateur sont stockées sur le serveur dans un objet persistant, nommé HttpSession. Il permet de stocker les informations saisies au fur et à mesure par l'utilisateur et de les relier à chaque requête grâce à l'identifiant passé en paramètre.

Il est commun dans le langage e-business de faire l'analogie avec un caddie (parfois shopping cart ou shopping basket) pour désigner ce système de suivi de session.

Réécriture d'URL

La méthode de réécriture d'URL consiste à passer des paires clé/valeur en paramètre dans l'URL. Ainsi, en passant en paramètre un identificateur unique de session, il est possible de le relier aux données stockées sur le serveur.

Toutes les URL dans les pages web du serveur ressembleront donc à quelque chose comme ceci (dans cet exemple purement fictif, l'id de session est 674684641) :

<a href="http://serveur/servlet/exemple?id=674684641">Lien hypertexte</a>

Ainsi avec cette technique, toutes les pages du site doivent contenir uniquement des URL dont l'ID de session a été ajouté dynamiquement, ce qui signifie que toutes les pages du site doivent être dynamiques.

D'autre part, étant donné que l'URL est limitée en longueur (255 caractères), il se peut qu'une partie des informations codées dans l'URL disparaissent. Enfin, bien que les sessions soient généralement limitées dans le temps (elles expirent), il se peut qu'un utilisateur tiers accède aux données de l'utilisateur à l'aide de l'URL.

Champs de formulaire cachés

La technique consistant à passer en paramètre un champ de formulaire contenant l'identifiant de session est similaire, à la différence près que les données sont envoyées par la méthode POST (plus sûre) :

<Input type="hidden" name="id" value="674684641">



Cette méthode implique par contre l'utilisation systèmatique d'un formulaire (clic sur un bouton submit) pour passer d'une page à une autre).

Utilisation de cookies

Les cookies sont des petits fichiers textes stockés sur le disque du client, permettant de stocker des paires clés/valeur. Le cookies concernant le domaine du site sur lequel un utilisateur surfe sont automatiquement envoyés dans les en-têtes HTTP lors de chaque requête du client.
D'autre part, lorsque le serveur désire créer un cookie sur le navigateur du client, il lui suffit d'envoyer des instructions dans les en-têtes de la réponse HTTP.

Le JSDK fournit une classe permettant de gérer de façon transparente les cookies, il s'agit de la classe Cookie.

Ainsi il est possible de stocker un identifiant de session de la manière suivante :

// Creation du cookie
Cookie C = new Cookie("id","674684641");

// definition de la limite de validite
C.setMaxAge(24*3600);

// envoi du cookie dans la reponse HTTP
res.addCookie(C);

Ce mécanisme est le plus intéressant pour stocker de petites informations. Toutefois l'utilisation de cookies pose quelques problèmes :
  • des utilisateurs désactivent les cookies par crainte
  • certains anciens navigateurs ne gèrent pas les cookies

L'objet HttpSession

L'objet HttpSession permet de mémoriser les données de l'utilisateur, grâce à une structure similaire à une table de hachage, permettant de relier chaque id de session à l'ensemble des informations relatives à l'utilisateur.

Ainsi en utilisant un mécanisme tel que les cookies (permettant d'associer une requête à un id) et l'objet HttpSession (permettant de relier des informations relatives à l'utilisateur à un id), il est possible d'associer facilement une requête aux informations de session !



L'objet HttpSession s'obtient grâce à la méthode getSession() de l'objet HttpServletRequest.

Gérer les sessions

La gestion des sessions se fait de la manière suivante :

  • Obtenir l'ID de session
    • Si GET: en regardant dans la requête
    • Si POST: en regardant dans les en-têtes HTTP
    • Sinon dans les cookies
  • Vérifier si une session est associé à l'ID
    • Si la session existe, obtenir les informations
    • Sinon
      • Générer un ID de Session
        • Si le navigateur du client accepte les cookies, ajouter un cookie contenant l'ID de session
        • Sinon ajouter l'ID de session dans l'URL
      • Enregistrer la session avec l'ID nouvellement créé

Obtenir une session

La méthode getSession() de l'objet HttpServletRequest permet de retourner la session relative à l'utilisateur (l'identification est faite de façon transparente par cookies ou réécriture d'URL) :

HttpSession getSession(boolean create)

L'argument create permet de créer une session relative à la requête lorsqu'il prend la valeur true.


Etant donnée que les cookies sont stockés dans le en-têtes HTTP, et que celles-ci doivent être les premières informations envoyées, la méthode getSession() doit être appelée avant tout envoi de données au navigateur (la méthode doit être invoquée avant toute écriture sur le flot de sortie de la servlet)
L'exemple suivant récupère la session associée à la requête de l'utilisateur et la crée si elle n'existe pas déjà :

public class Caddie extends HttpServlet { 
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
...
// Ecrit la reponse
out = response.getWriter();
...
}
}

Obtenir des informations d'une session

Pour obtenir une valeur précédemment stockée dans l'objet HttpSession, il suffit d'utiliser la méthode getAttribute() de l'objet HttpSession (celle-ci remplace dans la version 2.2 de l'API servlet la méthode getValue() qui était utilisée dans les versions 2.1 et inférieures).

Object getAttribute("cle")

La méthode getAttribute() retourne un objet (de type Object), il faut donc effectuer un surtypage pour obtenir un type élémentaire de données (un entier sera renvoyé sous forme d'objet Integer qu'il faudra convertir en int). Si l'attribut passé en paramètre n'existe pas, la méthode getAttribute() retourne la valeur null.
public class Caddie extends HttpServlet { 
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
// Recupere l'age de l'utilisateur
Age = (int)session.getAttribute("Age");

if (Age != null) {
// ... faire quelque chose
// Ecrit la reponse
out = response.getWriter();
}
else {
Age = new Integer(...);

// ... faire quelque chose d'autre
// Ecrit la reponse
out = response.getWriter();
}

}
}

Stocker des informations dans une session

Le stockage d'informations dans la session est similaire à la lecture. Il suffit d'utiliser la méthode setAttribute() (putvalue() pour les versions antérieures à la 2.2) en lui fournissant comme attributs la clé et la valeur associée.

Object setAttribute("cle","valeur")



L'exemple suivant stocke dans la session la page d'appel de la servlet (une page ayant fait un lien), ainsi que la date du dernier accès :

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

public class Caddie extends HttpServlet {
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
// Recupere l'age de l'utilisateur
session.setAttribute("referer",request.getHeader("Referer"));
}
}

Invalider une session

D'une manière générale, il est préférable de laisser une session se terminer seule (par expiration par exemple). Cependant, dans certains cas il peut être utile de supprimer manuellement une session (si l'utilisateur achète le contenu du caddie par exemple). Pour supprimer une session, il suffit de faire appel à la méthode invalidate() de l'objet HttpSession

public class Caddie extends HttpServlet { 
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Recupere la session
HttpSession session = request.getSession(true);
session.invalidate();

}
}

Autres méthodes de HttpSession


MéthodeDescription
long getCreationTime()(Retourne l'heure de la création de la session
Object getAttributes(String Name)Retourne l'objet stocké dans la session sous le nom Name, null s'il n'existe pas
String getId()Génère un identifiant de session
long getCreationTime()(Retourne la date de la requête précédente pour cette session
String[] getValueNames()(Retourne un tableau contenant le nom de toutes les clés de la session
Object getValue(String Name)Retourne l'objet stocké dans la session sous le nom Name, null s'il n'existe pas
void invalidate()Supprime la session
boolean isnew()(Retourne true si la session vient d'être créée, sinon false
void putValue(String Name, Object Value)Stocke l'objet Value dans la session sous le nom Name
void removeValue(String Name)Supprime l'élément Name de la session
void setAttribute(String Name, Object Value)Stocke l'objet Value dans la session sous le nom Name
int setMaxInactiveInterval(int interval)Définit l'intervalle de temps maximum entre deux requête avant que la session n'expire
int getMaxInactiveInterval(int interval)Retourne l'intervalle de temps maximum entre deux requête avant que la session n'expire


A voir également :

Ce document intitulé «  Servlets - Gestion des sessions  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.