• 10 heures
  • Facile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 03/09/2019

Gérez la session utilisateur

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Vous savez désormais comment mettre en place une cinématique d'écrans et interroger l'utilisateur. Afin de pouvoir réaliser une application Struts de base, il ne vous reste plus qu'à apprendre à gérer les sessions utilisateurs.

Je vous propose d'y aller progressivement en implémentant les cas d'utilisation : connexion et déconnexion d'un utilisateur.

Pas à pas : login/logout

Je vais m'organiser ainsi :

  • Je veux une classe d'Action permettant de gérer la connexion et la déconnexion de l'utilisateur.

  • La connexion se fera via une page de login permettant la saisie d'un identifiant et d'un mot de passe.

  • En cas d'erreur de connexion, l'utilisateur reste sur la page de login et un message d'erreur s'affiche.

  • En cas de connexion réussie, l'utilisateur est redirigé sur la page d'index.

  • A la déconnexion, l'utilisateur est redirigé sur la page d'index.

Configuration du mapping Struts

Concernant le mapping Struts, ici rien de bien compliqué ou de nouveau. Je crée deux actions Struts, login et logout, pointant vers les méthodes doLogin et doLogout de l'action LoginAction.

<!-- Actions Login/Logout -->
<action name="login" class="org.example.demo.ticket.webapp.action.LoginAction" method="doLogin">
    <result name="input">/jsp/login.jsp</result>
    <result name="success" type="redirectAction">index</result>
</action>
<action name="logout" class="org.example.demo.ticket.webapp.action.LoginAction" method="doLogout">
    <result type="redirectAction">index</result>
</action>

La classe LoginAction

Au niveau de la classe LoginAction, procédons par étape.

Tout d'abord, je crée la classe et y ajoute :

  • les attributs permettant de récupérer le login et le mot de passe saisis par l'utilisateur,

  • les méthodes doLogin et doLogout contenant la logique de l'action avec la sélection des results correspondants.

Pour le moment, je ne me soucis pas de la session.

package org.example.demo.ticket.webapp.action;

import org.apache.commons.lang3.StringUtils;
import com.opensymphony.xwork2.ActionSupport;

import org.example.demo.ticket.model.bean.utilisateur.Utilisateur;
import org.example.demo.ticket.model.exception.NotFoundException;
import org.example.demo.ticket.webapp.WebappHelper;


/**
 * Action de gestion de la connexion/déconnexion d'un utilisateur
 */
public class LoginAction extends ActionSupport {


    // ==================== Attributs ====================
    // ----- Paramètres en entrée
    private String login;
    private String password;


    // ==================== Getters/Setters ====================
    public String getLogin() {
        return login;
    }
    public void setLogin(String pLogin) {
        login = pLogin;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String pPassword) {
        password = pPassword;
    }


    // ==================== Méthodes ====================
    /**
     * Action permettant la connexion d'un utilisateur
     * @return input / success
     */
    public String doLogin() {
        String vResult = ActionSupport.INPUT;
        if (!StringUtils.isAllEmpty(login, password)) {
            try {
                Utilisateur vUtilisateur
                        = WebappHelper.getManagerFactory().getUtilisateurManager()
                                      .getUtilisateur(login, password);
                vResult = ActionSupport.SUCCESS;
            } catch (NotFoundException pEx) {
                this.addActionError("Identifiant ou mot de passe invalide !");
            }
        }
        return vResult;
    }


    /**
     * Action de déconnexion d'un utilisateur
     * @return success
     */
    public String doLogout() {
        return ActionSupport.SUCCESS;
    }
}
Ajouter des éléments en session (et les retirer)

Les classes d'action mappées dans Struts peuvent être de simples classes Java. Dans les chapitres précédents, j'ai fait hériter mes actions (GestionProjetAction et GestionUtilistateurAction) de la classe ActionSupport fournie par Struts. Ainsi mes actions avaient accès à quelques éléments de Struts comme l'ajout de messages d'erreur. Mais elles n'avaient pas accès à tout via cette classe de base.

Afin d'étendre les capacités des classes d'action, il est possible d'implémenter des interfaces de Struts : ce sont les interfaces nommées *Aware.

Pour accéder au contenu de la session utilisateur, je vais implémenter l'interface SessionAware. Cette interface indique à Struts que l'action implémente une méthode void setSession(Map<String,Object> session) et qu'elle doit être appelée avant d'entrer dans la méthode de l'action précisée dans le mapping.

// ...
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;

public class LoginAction extends ActionSupport implements SessionAware {

    // ----- Eléments Struts
    private Map<String, Object> session;

    @Override
    public void setSession(Map<String, Object> pSession) {
        this.session = pSession;
    }

    // ...
}

Ainsi, dans mon action, j'ai désormais accès à une Map correspondant au contenu de la session utilisateur !

Lors de la connexion utilisateur je vais donc pouvoir ajouter l'utilisateur en session :

public String doLogin() {
    String vResult = ActionSupport.INPUT;
    if (!StringUtils.isAllEmpty(login, password)) {
        try {
            Utilisateur vUtilisateur
                    = WebappHelper.getManagerFactory().getUtilisateurManager()
                                  .getUtilisateur(login, password);

            // Ajout de l'utilisateur en session
            this.session.put("user", vUtilisateur);

            vResult = ActionSupport.SUCCESS;
        } catch (NotFoundException pEx) {
            this.addActionError("Identifiant ou mot de passe invalide !");
        }
    }
    return vResult;
}

De même lors de la déconnexion, je vais pouvoir supprimer l'utilisateur de la session :

public String doLogout() {
    // Suppression de l'utilisateur en session
    this.session.remove("user");

    return ActionSupport.SUCCESS;
}

La vue

Au niveau de la vue, je vais faire un peu de refactoring. Je vais créer une JSP src/main/webapp/jsp/_include/header.jsp qui sera incluse en haut du <body> dans chaque JSP des vues (<%@ include file="./_include/header.jsp"%>).

Elle contiendra :

  • un lien vers la page de connexion si l'utilisateur n'est pas connecté ;

  • le nom et le prénom de l'utilisateur ainsi qu'un lien permettant la déconnexion si l'utilisateur est connecté ;

  • un ensemble de liens de navigation ;

  • l'affichage des messages d'information et d'erreur.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>

<header>
    <s:if test="#session.user">
            Utilisateur connecté :
            <s:property value="#session.user.prenom" />
            <s:property value="#session.user.nom" />

            <s:a action="logout">Déconnexion</s:a>
    </s:if>
    <s:else>
        <s:a action="login">Connexion</s:a>
    </s:else>
</header>

<nav>
    <s:a action="projet_list">
        <s:text name="nav.listProjet" />
    </s:a>

    <s:a action="projet_new">Créer un nouveau projet</s:a>
</nav>

<s:actionerror/>
<s:actionmessage/>

Il ne me reste plus qu'à créer la JSP de la page de connexion src/main/webapp/jsp/login.jsp :

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!DOCTYPE html>
<html>
<head>
    <%@ include file="./_include/head.jsp" %>
</head>

<body>
    <%@ include file="./_include/header.jsp" %>

    <h2>Connexion</h2>

    <s:form action="login">
        <s:textfield name="login" label="Identifiant" requiredLabel="true" />
        <s:password name="password" label="Mot de passe" requiredLabel="true" />

        <s:submit value="Connexion"/>
    </s:form>
</body>
</html>

Agir sur l' HttpSession

Si vous souhaitez agir directement sur l'objet HttpSession (ou d'autres éléments du contexte de la requête HTTP), votre action peut implémenter l'interface ServletRequestAware. Struts fera ainsi appel à la méthode setServletRequest(HttpServletRequest) pour injecter l'objet HttpServletRequest dans votre action.

Par exemple, dans la classe LoginAction, je peux invalider la session à la déconnexion de l'utilisateur :

package org.example.demo.ticket.webapp.action;

import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.interceptor.ServletRequestAware;
import com.opensymphony.xwork2.ActionSupport;


/**
 * Action de gestion de la connexion/déconnexion d'un utilisateur
 */
public class LoginAction extends ActionSupport implements ServletRequestAware, SessionAware {

    private HttpServletRequest servletRequest;

    @Override
    public void setServletRequest(HttpServletRequest pRequest) {
        this.servletRequest = pRequest;
    }


    /**
     * Action de déconnexion d'un utilisateur
     * @return success
     */
    public String doLogout() {
        // Invalidation de la session
        this.servletRequest.getSession().invalidate();

        return ActionSupport.SUCCESS;
    }


    // ...
}

Attention, danger

Sachez qu'il existe plusieurs types d'attaque liés à la gestion des sessions, comme la fixation de session.

Plusieurs solutions sont envisageables et il y a de bonnes pratiques à respecter.

Il est par exemple recommandé d'invalider la session lors du logout (avec HttpServletRequest.getSession().invalidate()) et de changer l'identifiant de session lors du login (avec HttpServletRequest.changeSessionId()).

Je ne vais pas trop m'attarder sur ce sujet car ce n'est pas l'objet de ce cours : il y a beaucoup de choses à dire et pas mal de facteurs qui entrent en compte.

Rien ne presse pour le moment, mais je vous conseille de vous documenter sur tout cela quand vous développerez vos premières réelles applications.

Les sources sont très nombreuses sur internet, comme celles de l'OWASP par exemple :

Conclusion

Comme vous avez pu le constater, la gestion de la session avec Struts est très simple.

C'est cool, vous avez maintenant acquis les bases pour créer votre première application Struts. Dans la partie suivante, je rentrerai un peu plus en profondeur dans le cœur de Struts et vous montrerai comment adresser des aspects plus techniques pour un développement plus professionnel !

Exemple de certificat de réussite
Exemple de certificat de réussite