Effectuer l'authentification de L'utilisateur dans Java EE / JSF en utilisant la vérification de sécurité j
je me demande Quelle est l'approche actuelle en ce qui concerne l'authentification de l'utilisateur pour une application web utilisant JSF 2.0 (et si des composants existent) et les mécanismes de base Java EE 6 (connexion/vérification des permissions/déconnexions) avec l'information utilisateur détenue dans une entité JPA. Le tutoriel Java EE D'Oracle est un peu clairsemé à ce sujet (il ne traite que les servlets).
C'est sans faisant usage de tout un autre cadre, comme ressort-sécurité (acegi), ou Couture, mais essayer de s'en tenir, si possible, à la nouvelle plate-forme Java EE 6 (profil web).
4 réponses
après avoir cherché sur le Web et essayé de nombreuses façons différentes, voici ce que je suggérerais pour l'authentification Java EE 6:
mettre en place le domaine de la 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 domaine JDBC qui pourrait authentifier les utilisateurs basés sur le nom d'utilisateur et les mots de passe MD5-hashé dans ma table de base de données:
http://blog.gamatam.com/2009/11/jdbc-realm-setup-with-glassfish-v3.html
Remarque: le post parle d'un utilisateur et un groupe table dans la base de données. J'avais une classe D'utilisateurs avec un attribut UserType enum mappé via javax.la persistance des annotations à 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 group et ça a bien fonctionné.
Use authentification form:
toujours en suivant l'article de blog ci-dessus, configurer votre web.xml et sun-web.xml, mais au lieu d'utiliser l'authentification de base, utilisez FORM (en fait, peu importe lequel vous utilisez, mais j'ai fini par utiliser FORM). Utilisez le HTML standard, pas le JSF .
puis utiliser le Conseil de BalusC ci-dessus sur lazy initialisant l'information de l'utilisateur à partir de la base de données. Il a suggéré de le faire dans un bean géré obtenir le principal du visage contexte. J'ai utilisé, à la place, un haricot de session stateful pour stocker des 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 le Gestionnaire D'entités EJB, obtenir les informations D'utilisateur à partir de la base de données et stocker dans mon SessionInformation
EJB.
Déconnexion:
j'ai aussi cherché la meilleure façon de me déconnecter. Le meilleur que j'ai trouvé 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);
// Destroys the session for this user.
if (session != null)
session.invalidate();
// Redirects back to the initial page.
response.sendRedirect(request.getContextPath());
}
}
bien que mon la réponse est vraiment tardive compte tenu de la date de la question, j'espère que cela aidera d'autres personnes qui finissent ici à partir de Google, tout comme je l'ai fait.
Ciao,
Vítor Souza
je suppose que vous voulez formulaire d'authentification basée sur les à l'aide descripteurs de déploiement et j_security_check
.
vous pouvez également le faire dans JSF en utilisant simplement les mêmes noms de champs prédéfinis j_username
et j_password
comme démontré dans le tutoriel.
E. G.
<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 pourriez faire le chargement paresseux dans le User
getter pour vérifier si le User
est déjà connecté et si non, vérifiez si le Principal
est présent dans la requête et si oui, obtenez 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 logout HttpServletRequest#logout()
( User
à null!). Vous pouvez obtenir une poignée du HttpServletRequest
dans JSF par ExternalContext#getRequest()
. Vous peut aussi simplement invalider la session.
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "login?faces-redirect=true";
}
pour le reste (définition des utilisateurs, des rôles et des contraintes dans le descripteur de déploiement et le 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 le nouveau Servlet 3.0 HttpServletRequest#login()
pour faire un login programmatique au lieu d'utiliser j_security_check
qui peut ne pas être en soi accessible à un répartiteur dans certains serveurs. Dans ce cas, vous pouvez utiliser un formulaire fullworthy JSF et un haricot avec username
et password
propriétés et une méthode login
qui ressemblent à 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 cette vue scoped managed bean qui se souvient aussi de la page initialement demandée:
@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.
}
ainsi le User
est accessible en JSF EL par #{user}
.
il convient de mentionner qu'il s'agit d'une option permettant de laisser complètement les problèmes d'authentification au contrôleur frontal, par exemple un serveur web Apache et d'évaluer la requête HttpServletRequest.getRemoteUser () à la place, qui est la représentation JAVA pour la variable D'environnement REMOTE_USER. Cela permet également des conceptions de log in sophistiquées telles que l'authentification Shibboleth. Le filtrage des requêtes vers un conteneur servlet via un serveur web est une bonne conception pour les environnements de production, Souvent mod_jk est utilisé faire.
the issue Httpservlequest.login ne définit pas l'état d'authentification dans la session a été corrigé dans 3.0.1. Mettez glassfish à la dernière version et c'est fini.
mise à Jour est assez simple:
glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update