2009-09-24 6 views
35

Je voudrais voir une simple application de connexion, pas aussi simple que this cependant. Ce que je voudrais réaliser est une compréhension sur comment JSF fonctionne, j'ai développé beaucoup d'ASP.NET où vous avez le code derrière et où vous pouvez juste vérifier si une session a été créée lors de la connexion.Sécurité de base dans JSF

Une solution similaire dans JSF serait géniale.

C'est essentiellement ce que je veux atteindre:

  • page Connexion
  • IF OK
    • Créer session et retour "succès"
  • IF FAIL
    • return "échec"

(Le "succès" et l'échec sont mises en correspondance à faces-config.xml)

le succès page Je veux être certain que l'utilisateur est connecté, si un ne devrait pas être capable de naviguer vers "success.jspx" si vous n'avez pas la bonne session.

+1

Connexes: http://stackoverflow.com/questions/2206911/best-way-for-user-authentication-on-javaee-6-using-jsf-2-0/2207147#2207147 Ou si vous êtes ouvert aux bibliothèques tierces comme Shiro, puis http://balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html – BalusC

Répondre

44

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

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

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

Ce filtre protège les ressources dans le répertoire restricted tel que 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> 

La mise en œuvre de 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 grain 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 e 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 de redirection/mécanisme a été choisi par souci de concision plutôt que toute sorte de bonnes pratiques; voir le Servlet API pour plus d'options.)

+0

pourriez-vous préciser en quoi cela est différent de sécurité gérée par conteneur? & comment préférer l'un à l'autre après avoir considéré les avantages/désavantages de chacun? –

+0

@Marcos - cela mérite vraiment d'être sa propre question, en référence peut-être celle-ci. – McDowell

+0

En fait, j'avais déjà posté quelque chose de similaire ici: http: //stackoverflow.com/questions/7872265/protected-urls-leaking-unprotected-components-of-the-webapge-to-unauthenticated/7875236#7875236 –

4

Si vous êtes prêt à essayer une approche un peu plus avancée, alors je suggère de regarder dans printemps-sécurité + 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 devraient être protégées en utilisant les aspects.

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

A Tutoriel: http://ocpsoft.com/java/acegi-spring-security-jsf-login-page/

3

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

Here is a tutorial sur comment y parvenir avec glassfish et jsf.

2

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), ne pas essayer de montrer un actualy écran, il calles de la charge le javascript startupSubmit() et 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() dans StartupBean définit une variable appelée à true (par défaut à false), puis saute à first.xhtml. Vous pouvez utiliser tous les critères que vous désirez pour déterminer si l'autorisation est définie sur true ... comme 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; 
} 
} 

modèle.xhtml. Dans template.xhtml, juste à l'intérieur du formulaire, vous placez un h: ou p: panelGrid et ne le restituez que si startupBean.authorized est vrai. Le seul moyen pour un utilisateur d'accéder aux pages contenues dans le modèle est de commencer 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> 

Donc, c'est ma solution. Je l'ai testé assez minutieusement et cela semble fonctionner correctement.

+0

Le '@ManagedBean L'attribut '* nom * dans' StartupBean' est inutile car il aura ce nom par défaut. – rbento