Question

Je me demande ce que l'approche actuelle concernant l'authentification utilisateur pour une application web faisant usage de JSF 2.0 (et si tous les composants existent) et Java EE 6 mécanismes de base (autorisations de connexion / contrôle / déconnexions) avec les informations utilisateur détiennent dans une entité JPA. Le tutoriel Java EE Oracle est un peu clairsemée sur ce (poignées seulement servlets).

sans ou Seam, mais en essayant de rester si possible avec la nouvelle plate-forme Java EE 6 (profil web) faisant usage d'un cadre tout autre, comme le Printemps-sécurité (Acegi) si possible .

Était-ce utile?

La solution

Après une recherche sur le Web et essayer de différentes façons, voici ce que je vous suggère pour l'authentification Java EE 6:

Configurer le domaine de la sécurité:

Dans mon cas, j'avais les utilisateurs dans la base de données. Donc, je suivais ce blog pour créer un royaume JDBC qui pourrait authentifier les utilisateurs basés sur le nom d'utilisateur et mots de passe de hachage MD5 dans ma table de base de données:

http: //blog.gamatam. com / 2009/11 / jdbc-royaume-setup avec-GlassFish-v3.html

Note: les pourparlers de poste sur un utilisateur et une table de groupe dans la base de données. J'ai eu une classe d'utilisateurs avec un attribut ENUM UserType cartographié via des annotations javax.persistence à la base de données. J'ai configuré le royaume avec la même table pour les utilisateurs et les groupes, en utilisant la colonne userType comme la colonne de groupe et il a bien fonctionné.

Utiliser l'authentification de formulaire:

Toujours en suivant le message de blog ci-dessus, configurez votre web.xml et sun-web.xml, mais au lieu d'utiliser l'authentification de base, utilisez le formulaire (en fait, il n'a pas d'importance que vous utilisez, mais j'ai fini en utilisant le formulaire ). Utilisez le code HTML standard, pas le JSF.

Utilisez ensuite la pointe de BalusC ci-dessus sur l'initialisation paresseuse les informations utilisateur de la base de données. Il suggère de le faire dans un bean géré obtenir le principal du contexte des visages. Je, au contraire, un bean session stateful pour stocker des informations de session pour chaque utilisateur, donc j'injectais le contexte de la session:

 @Resource
 private SessionContext sessionContext;

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

Déconnexion:

J'ai aussi regardé pour trouver la meilleure façon de se déconnecter. Le meilleur que j'ai trouvé utilise 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);

   // Destroys the session for this user.
   if (session != null)
        session.invalidate();

   // Redirects back to the initial page.
   response.sendRedirect(request.getContextPath());
  }
 }

Bien que ma réponse est vraiment en retard compte tenu de la date de la question, j'espère que cela aide d'autres personnes qui se retrouvent ici de Google, comme je l'ai fait.

Ciao,

Vítor Souza

Autres conseils

Je suppose que vous voulez une authentification basée sur utilisant descripteurs de déploiement et j_security_check.

Vous pouvez aussi le faire dans JSF en utilisant simplement les mêmes noms de champs predefinied j_username et j_password comme l'a démontré dans le tutoriel.

par exemple.

<form action="j_security_check" method="post">
    <h:outputLabel for="j_username" value="Username" />
    <h:inputText id="j_username" />
    <br />
    <h:outputLabel for="j_password" value="Password" />
    <h:inputSecret id="j_password" />
    <br />
    <h:commandButton value="Login" />
</form>

Vous pouvez faire le chargement paresseux 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 demande et si oui, alors obtenir le User associé à j_username.

package com.stackoverflow.q2206911;

import java.io.IOException;
import java.security.Principal;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@SessionScoped
public class Auth {

    private User user; // The JPA entity.

    @EJB
    private UserService userService;

    public User getUser() {
        if (user == null) {
            Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
            if (principal != null) {
                user = userService.find(principal.getName()); // Find User by j_username.
            }
        }
        return user;
    }

}

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

Pour faire un HttpServletRequest#logout() (et mettre User à null!). Vous pouvez obtenir une poignée du HttpServletRequest en JSF par ExternalContext#getRequest() . Vous pouvez aussi annuler la session tout à fait.

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

Pour le reste (la définition des utilisateurs, des rôles et des contraintes dans le descripteur de déploiement et domaine), il suffit de suivre le tutoriel Java EE 6 et la documentation servletcontainer de la manière habituelle.


Mise à jour : vous pouvez également utiliser la nouvelle Servlet 3.0 HttpServletRequest#login() pour faire une connexion programmatique au lieu d'utiliser j_security_check qui ne peut pas par soi-être accessible par un répartiteur dans certains servletcontainers. Dans ce cas, vous pouvez utiliser une forme fullworthy JSF et un haricot avec des propriétés username et password et une méthode de login qui ressemble à ceci:

<h:form>
    <h:outputLabel for="username" value="Username" />
    <h:inputText id="username" value="#{auth.username}" required="true" />
    <h:message for="username" />
    <br />
    <h:outputLabel for="password" value="Password" />
    <h:inputSecret id="password" value="#{auth.password}" required="true" />
    <h:message for="password" />
    <br />
    <h:commandButton value="Login" action="#{auth.login}" />
    <h:messages globalOnly="true" />
</h:form>

Et ce point de vue SCOPED bean géré qui se souvient aussi la page demandée initialement:

@ManagedBean
@ViewScoped
public class Auth {

    private String username;
    private String password;
    private String originalURL;

    @PostConstruct
    public void init() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);

        if (originalURL == null) {
            originalURL = externalContext.getRequestContextPath() + "/home.xhtml";
        } else {
            String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);

            if (originalQuery != null) {
                originalURL += "?" + originalQuery;
            }
        }
    }

    @EJB
    private UserService userService;

    public void login() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();

        try {
            request.login(username, password);
            User user = userService.find(username, password);
            externalContext.getSessionMap().put("user", user);
            externalContext.redirect(originalURL);
        } catch (ServletException e) {
            // Handle unknown username/password in request.login().
            context.addMessage(null, new FacesMessage("Unknown login"));
        }
    }

    public void logout() throws IOException {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        externalContext.invalidateSession();
        externalContext.redirect(externalContext.getRequestContextPath() + "/login.xhtml");
    }

    // Getters/setters for username and password.
}

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

Il convient de mentionner qu'il est une option de laisser complètement les problèmes d'authentification au contrôleur avant, par exemple un serveur Web Apache et évaluer la HttpServletRequest.getRemoteUser () à la place, qui est la représentation de JAVA pour la variable d'environnement REMOTE_USER. Cela permet également de journal sophistiqué dans des conceptions telles que l'authentification Shibboleth. Les demandes de filtrage à un conteneur de servlet via un serveur Web est une bonne conception pour les environnements de production, souvent mod_jk est utilisé pour le faire.

La question HttpServletRequest.login ne état d'authentification définie pas en session a été fixée en 3.0.1. Mise à jour GlassFish à la dernière version et vous avez terminé.

La mise à jour est assez simple:

glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top