web-dev-qa-db-fra.com

Sécurité de base dans JSF

J'aimerais voir une simple application de connexion, pas aussi simple que this cependant.

Ce que je voudrais atteindre, c'est une compréhension du fonctionnement de JSF, j'ai développé beaucoup d'ASP.NET où vous avez le code derrière et où vous pouvez simplement vérifier si une session a été créée lors de la connexion.

Une solution similaire dans JSF serait formidable.

C'est essentiellement ce que je veux réaliser:

  • Page de connexion
  • SI OK
    • Créer une session et retourner le "succès"
  • EN CAS D'ÉCHEC
    • retourner "échec"

(Le "succès" et l'échec sont mappés sur faces-config.xml)

Sur la page de réussite, je veux être certain que l'utilisateur est connecté, donc on ne devrait pas pouvoir naviguer vers "success.jspx" si vous n'avez pas la bonne session.

36
Filip Ekberg

Il n'y a pas de fonctionnalité d'authentification inhérente dans le noyau JSF au-delà de la possibilité d'utiliser des éléments tels que les attributs des composants rendered orientés vers la sécurité basée sur les rôles.

Par défaut, une application JSF s'appuie sur les mêmes mécanismes de sécurité gérés par conteneur que le composant Web qui la contient ( tutoriel JEE5 ). Les frameworks tiers comme Seam peuvent fournir des alternatives.

Si vous souhaitez ajouter votre propre sécurité d'application, un filtre de servlet est l'un des mécanismes les plus simples.

Ce filtre protège les ressources sous le répertoire restricted comme défini dans web.xml:

  <filter>
    <filter-name>AuthenticationFilter</filter-name>
    <filter-class>restricted.AuthenticationFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>AuthenticationFilter</filter-name>
    <url-pattern>/restricted/*</url-pattern>
  </filter-mapping>

L'implémentation de la classe de filtre:

public class AuthenticationFilter implements Filter {
  private FilterConfig config;

  public void doFilter(ServletRequest req, ServletResponse resp,
      FilterChain chain) throws IOException, ServletException {
    if (((HttpServletRequest) req).getSession().getAttribute(
        AuthenticationBean.AUTH_KEY) == null) {
      ((HttpServletResponse) resp).sendRedirect("../restricted_login.faces");
    } else {
      chain.doFilter(req, resp);
    }
  }

  public void init(FilterConfig config) throws ServletException {
    this.config = config;
  }

  public void destroy() {
    config = null;
  }
}

Un bean de connexion défini dans faces-config.xml:

public class AuthenticationBean {
  public static final String AUTH_KEY = "app.user.name";

  private String name;
  public String getName() { return name; }
  public void setName(String name) { this.name = name; }

  public boolean isLoggedIn() {
    return FacesContext.getCurrentInstance().getExternalContext()
        .getSessionMap().get(AUTH_KEY) != null;
  }

  public String login() {
    FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(
        AUTH_KEY, name);
    return "secret";
  }

  public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
        .remove(AUTH_KEY);
    return null;
  }
}

Le formulaire de connexion JSF dans le restricted_login.jsp page:

  <f:view>
    <p><a href="restricted/secret.faces">try to go to secret
    page</a></p>
    <h:form>
    Username:
    <h:panelGroup rendered="#{not authenticationBean.loggedIn}">
        <h:inputText value="#{authenticationBean.name}" />
        <h:commandButton value="login"
          action="#{authenticationBean.login}" />
      </h:panelGroup>
      <h:commandButton value="logout"
        action="#{authenticationBean.logout}"
        rendered="#{authenticationBean.loggedIn}" />
    </h:form>
  </f:view>

(L'URL/mécanisme de redirection a été choisi pour plus de brièveté que pour toute sorte de meilleure pratique; voir API Servlet pour plus d'options.)

46
McDowell

Si vous êtes prêt à essayer une approche un peu plus avancée, je vous suggère de vous pencher sur Spring-Security + JSF. Il fonctionne comme un charme.

Vous pouvez écrire votre application comme si elle n'était pas sous sécurité, puis configurer simplement les zones qui doivent être protégées à l'aide d'aspects.

Sécurité de printemps: http://static.springsource.org/spring-security/site/

Un tutoriel: http://ocpsoft.com/Java/acegi-spring-security-jsf-login-page/

4
Tomas F

La meilleure façon de le faire serait d'utiliser la sécurité gérée par conteneur.

Voici un tutoriel sur comment y parvenir avec glassfish et jsf.

3
gordan

Si vous utilisez des modèles, j'ai constaté que vous n'avez pas vraiment besoin d'un filtre.

index.jsp

<jsp:forward page="startup.faces"></jsp:forward>

startup.xhtml (.faces), n'essaie pas vraiment d'afficher un écran, il appelle le javascript startupSubmit () à la charge et qui clique sur le bouton. Cela envoie le flux directement à la méthode start () dans StartupBean.Java.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0     Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
.
.
 <script type="text/javascript">
 function startupSubmit() {
  **document.getElementById('startupForm:startupBtn').click();**
 }
 </script>
 <h:body onload="startupSubmit()">
 <h:form id="startupForm">
 <p:commandButton id="startupBtn" value="" action="#{startupBean.start}" ajax="false" />  
 </h:form>
 </h:body>
</html>

StartupBean.Java (ne fait pas partie du template.xhtml ci-dessous). La méthode start () de StartupBean définit une variable appelée autorisé sur true (elle vaut par défaut false), puis passe à first.xhtml. Vous pouvez utiliser tous les critères que vous souhaitez pour déterminer si autorisé est défini sur true ... tels que les critères de connexion.

package gov.irs.eservices.managementBeans;

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

@ManagedBean(name="startupBean")
@SessionScoped
public class StartupBean {

private boolean authorized;

public StartupBean() {
}

public String start() {
    **setAuthorized(true);**
    return "first";
}

public boolean isAuthorized() {
    return authorized;
}

public void setAuthorized(boolean authorized) {
    this.authorized = authorized;
}
}

template.xhtml. Dans template.xhtml, juste à l'intérieur du formulaire, vous placez un h: ou p: panelGrid et vous le rendez uniquement si startupBean.authorized est vrai. Le seul moyen pour un utilisateur d'accéder aux pages contenues dans le modèle est de passer d'abord par StartupBean.Java.

<f:view>
<div id="container">
<h:form id="templateForm">
**<p:panelGrid rendered="#{startupBean.authorized}">**
    <div id="header">
        <ui:include src="header.xhtml" />
    </div>

    <div id="wrapper">
        <div id="firstId">
            <ui:insert name="first"></ui:insert>
        </div>
.
.  <!-- MORE PAGES -->
.
.
    </div>

    <div id="footer">
        <ui:include src="footer.xhtml" />
    </div>
</p:panelGrid>
</h:form>
</div>      
</f:view>

Voilà ma solution. Je l'ai testé assez soigneusement et cela semble bien fonctionner.

2
DougMH