156 votes

Effectuer l'authentification de l'utilisateur en Java EE / JSF en utilisant j_security_check

Je me demande quelle est l'approche actuelle en matière d'authentification des utilisateurs pour une application web utilisant JSF 2.0 (et s'il existe des composants) et les mécanismes de base de Java EE 6 (connexion/vérification des autorisations/déconnexion) avec les informations utilisateur stockées dans une entité JPA. Le tutoriel Oracle Java EE est un peu maigre à ce sujet (ne traite que des servlets).

Ceci est sans utiliser un autre framework complet, comme Spring-Security (acegi), ou Seam, mais en essayant de rester de préférence avec la nouvelle plateforme Java EE 6 (profil web) si possible.

150voto

BalusC Points 498232

Je suppose que vous voulez l'authentification basée sur le formulaire en utilisant des descripteurs de déploiement et j_security_check.

Vous pouvez également le faire en JSF en utilisant simplement les mêmes noms de champs prédéfinis j_username et j_password comme démontré dans le tutoriel.

Par exemple:

Vous pouvez effectuer un chargement différé dans le getter User pour vérifier si le User est déjà connecté et sinon, vérifier si le Principal est présent dans la requête et si c'est le cas, obtenir le User associé à j_username.

package com.stackoverflow.q2206911;

// Import des classes nécessaires

public class Auth {

    private User user; // L'entité JPA.

    private UserService userService; // Le service de l'utilisateur.

    public User getUser() {
        // Implémentation du getter
    }

}

Le User est évidemment accessible dans JSF EL par #{auth.user}.

Pour se déconnecter, utilisez un HttpServletRequest#logout() (et définissez User sur null!). Vous pouvez obtenir une instance du HttpServletRequest dans JSF en utilisant ExternalContext#getRequest(). Vous pouvez aussi simplement invalider la session complètement.

public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    return "login?faces-redirect=true";
}

Pour le reste (définir les utilisateurs, les rôles et les contraintes dans le descripteur de déploiement et le royaume), suivez simplement le tutoriel Java EE 6 et la documentation du conteneur de servlets de la manière habituelle.


Mise à jour : vous pouvez également utiliser le nouveau HttpServletRequest#login() de Servlet 3.0 pour effectuer une connexion programmatique au lieu d'utiliser j_security_check qui peut ne pas être accessible par un dispatcher dans certains conteneurs de servlets. Dans ce cas, vous pouvez utiliser un formulaire JSF complet et un bean avec les propriétés username et password et une méthode login qui ressemble à ceci :

Et ce bean géré à portée de vue qui se souvient également de la page demandée initialement :

@ManagedBean
@ViewScoped
public class Auth {

    // Implémentation du bean géré et des méthodes

}

De cette façon, le User est accessible dans JSF EL par #{user}.

85voto

Après avoir cherché sur le Web et essayé de nombreuses façons différentes, voici ce que je recommanderais pour l'authentification Java EE 6 :

Configurer le domaine de sécurité :

Dans mon cas, j'avais les utilisateurs dans la base de données. J'ai donc suivi ce billet de blog pour créer un JDBC Realm qui pouvait authentifier les utilisateurs en fonction du nom d'utilisateur et des mots de passe hachés en MD5 dans ma table de base de données :

http://blog.gamatam.com/2009/11/jdbc-realm-setup-with-glassfish-v3.html

Remarque : le billet parle d'une table utilisateur et d'une table de groupe dans la base de données. J'avais une classe Utilisateur avec un attribut enum UserType mappé via des annotations javax.persistence à la base de données. J'ai configuré le domaine avec la même table pour les utilisateurs et les groupes, en utilisant la colonne userType comme colonne de groupe et cela a fonctionné correctement.

Utiliser l'authentification par formulaire :

En suivant toujours le billet de blog ci-dessus, configurez votre web.xml et sun-web.xml, mais au lieu d'utiliser l'authentification BASIC, utilisez FORM (en fait, peu importe lequel vous utilisez, mais j'ai fini par utiliser FORM). Utilisez le standard HTML , pas le JSF .

Ensuite, utilisez le conseil de BalusC ci-dessus sur l'initialisation paresseuse des informations utilisateur à partir de la base de données. Il a suggéré de le faire dans un bean géré en récupérant le principal du contexte faces. J'ai utilisé, au lieu de cela, un bean de session stateful pour stocker les informations de session pour chaque utilisateur, j'ai donc injecté le contexte de session :

@Resource
 private SessionContext sessionContext;

Avec le principal, je peux vérifier le nom d'utilisateur et, en utilisant l'EJB Entity Manager, obtenir les informations de l'utilisateur à partir de la base de données et les stocker dans mon EJB SessionInformation.

Déconnexion :

J'ai également cherché la meilleure façon de se déconnecter. La meilleure que j'ai trouvée est d'utiliser un Servlet :

@WebServlet(name = "LogoutServlet", urlPatterns = {"/logout"})
public class LogoutServlet extends HttpServlet {
 @Override
 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  HttpSession session = request.getSession(false);

  // Détruit la session pour cet utilisateur.
  if (session != null)
       session.invalidate();

  // Redirige vers la page initiale.
  response.sendRedirect(request.getContextPath());
 }
}

Même si ma réponse est vraiment tardive étant donné la date de la question, j'espère que cela aidera d'autres personnes qui se retrouvent ici depuis Google, tout comme moi.

Ciao,

Vítor Souza

7voto

Paramaeleon Points 1030

Il convient de mentionner qu'il est possible de laisser complètement les problèmes d'authentification au contrôleur frontal, par exemple un serveur Web Apache, et d'évaluer HttpServletRequest.getRemoteUser() à la place, qui est la représentation JAVA de la variable d'environnement REMOTE_USER. Cela permet également des conceptions de connexion sophistiquées telles que l'authentification Shibboleth. Filtrer les requêtes vers un conteneur de servlets via un serveur Web est une bonne conception pour les environnements de production, souvent mod_jk est utilisé pour cela.

4voto

Hans Bacher Points 41

Le problème HttpServletRequest.login ne définit pas l'état d'authentification dans la session a été corrigé dans la version 3.0.1. Mettez à jour GlassFish vers la dernière version et le tour est joué.

La mise à jour est assez simple:

glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update

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