2009-09-24 35 views
35

我希望看到一個簡單的登錄應用程序,但不像this那麼簡單。JSF中的基本安全性

我想要實現的是對JSF如何工作的理解,我已經開發了大量ASP.NET,其中有代碼隱藏在後面,以及在何處可以檢查會話是否在登錄時創建。

在JSF中的類似解決方案將是偉大的。

這基本上是我想達到什麼:

  • 登錄頁面
  • 如果正常
    • 創建會話並返回 「成功」
  • 如果失敗則
    • 返回「失敗」

(「成功」和失敗映射到faces-config.xml中)

在成功頁我想某些用戶登錄,所以一如果您沒有獲得正確的會話,則無法導航到「success.jspx」。

+1

相關:http://stackoverflow.com/questions/2206911/best-way-for-user-authentication-on-javaee-6-using-jsf-2-0/2207147#2207147或者如果你打開到Shiro等第三方庫,然後http://balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html – BalusC

回答

44

除了能夠使用類似於基於角色的安全性的組件rendered之外,核心JSF中沒有固有的身份驗證功能。

默認情況下,JSF應用程序依賴與包含它的Web組件相同的容器管理安全機制(JEE5 tutorial)。像Seam這樣的第三方框架可以提供替代方案。

如果您想添加自己的應用程序安全性,servlet filter是更簡單的機制之一。

<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> 

過濾器類實現:

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; 
    } 
} 

的登錄豆在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; 
    } 
} 

此過濾器作爲web.xml定義的restricted目錄下的保護資源JSF登錄表單Ërestricted_login.jsp頁:

<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> 

(被選定爲簡便起見,而不是任何形式的最佳實踐的重定向URL /機制;請參閱Servlet API以獲取更多選項。)

+0

你能澄清這是如何不同於容器管理的安全?以及如何在考慮每個人的advtges/disadvantagevntages之後更喜歡哪一個? –

+0

@Marcos - 這真的值得成爲它自己的問題,可能引用這個問題。 – McDowell

+0

其實我已經在這裏發佈了類似的東西:http://stackoverflow.com/questions/7872265/protected-urls-leaking-unprotected-components-of-the-webapge-to-unauthenticated/7875236#7875236 –

3

做到這一點是使用容器的最佳方式管理的安全性。

Here is a tutorial關於如何實現與glassfish和​​。

2

如果您使用模板,我發現您並不需要過濾器。

的index.jsp

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

startup.xhtml(.faces),不actualy嘗試顯示屏幕,它卡列斯的JavaScript startupSubmit()上的負載,並且點擊按鈕。這會將流直接發送到StartupBean.java中的start()方法。

<!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(不是下面的template.xhtml的一部分)。 StartupBean中的start()方法將名爲authorized的變量設置爲true(默認爲false),然後跳轉到first.xhtml。您可以使用您希望確定授權是否設置爲true的任何標準...例如登錄標準。

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。在template.xhtml中,只需在窗體內部放置一個h:或p:panelGrid,並只在startupBean.authorized爲true時才渲染它。用戶可以訪問模板中包含的頁面的唯一方法是,如果他們首先通過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> 

所以,這是我的解決方案。我已經測試它非常徹底,它似乎工作正常。

+0

@ManagedBean 'StartupBean'中的'* name *'屬性是不需要的,因爲默認情況下它會得到這個名字。 – rbento