如何使用 Acegi 保護在 servlet 容器中運行的 JavaServer Faces (JSF) 應用程序。本文首先解釋 Acegi 針對此目標提供的特性,並澄清一些關於使用 Acegi和JSF 的常見誤解。然後提供一個簡單的 web.xml 文件,可以用來部署 Acegi,從而保護 JSF應用程序。然後深入探討 Acegi和JSF 組件,了解在部署 web.XML 文件和用戶訪問 JSF應用程序時所發生的事件。本文最後提供了一個由 Acegi 保護的示例 JSF應用程序。
無需編寫 Java 代碼即可添加安全性
回顧一下本系列的第一個示例 Acegi 應用程序(請參閱 第 1 部分 中的 “一個簡單 Acegi 應用程序” 一節)。該應用程序使用 Acegi 提供了以下安全特性:
◆當一個未經驗證的用戶試圖訪問受保護的資源時,提供一個登錄頁面。
◆將授權用戶直接重定向到所需的受保護資源。
◆如果用戶未被授權訪問受保護資源,提供一個訪問拒絕頁面。
回想一下,您無需編寫任何 Java 代碼就能獲得這些特性。只需要對 Acegi 進行配置。同樣,在 JSF應用程序中,無需編寫任何 Java 代碼,也應該能夠從 Acegi 實現相同的特性。
澄清誤解
其他一些作者似乎認為將 Acegi 與 JSF 集成需要 JSF應用程序提供登錄頁面(參見 參考資料)。這種觀點並不正確。在需要時提供登錄頁面,這是 Acegi 的職責。確保登錄頁面在安全會話期間只出現一次,這也是 Acegi 的職責。然後,經過身份驗證和授權的用戶可以訪問一個受保護資源,無需重復執行登錄過程。
如果使用 JSF 提供登錄頁面,將會發生兩個主要的問題:
◆當需要時,沒有利用 Acegi 的功能提供登錄頁面。必須編寫 Java 代碼實現所有邏輯來提供登錄頁面。
◆至少需要編寫一些 Java 代碼將用戶憑證(用戶名和密碼)從 JSF 的登錄頁面移交到 Acegi。
Acegi 的目的是避免編寫 Java 安全代碼。如果使用 JSF 提供登錄頁面,則沒有實現這一用途,並且會引發一系列其他 JSF-Acegi 集成問題,所有這些問題都源於 “Acegi 是用來提供可配置安全性” 這一事實。如果試圖使用 JSF 來完成 Acegi 的工作,將會遇到麻煩。
本文余下部分將解釋並演示獨立於 Acegi 的 JSF應用程序開發,並在稍後配置 Acegi 以保護 JSF應用程序 — 無需編寫任何 Java 代碼。首先看一下 web.XML 文件,可以部署該文件保護 JSF應用程序。
部署 Acegi 保護 JSF應用程序
清單 1 展示了一個 web.XML 文件(通常稱為部署描述符),可以使用這個文件部署 Acegi,從而保護運行在 servlet 容器(比如 apache Tomcat)中的 JSF應用程序:
清單 1. 用於部署 Acegi 和 servlet 容器中的 JSF 的 web.XML 文件
- <?XML version="1.0"?>
- <!DOCTYPE web-app PUBLIC-//Sun Microsystems, Inc.//DTD
Web Application 2.3//EN http://Java.sun.com/dtd/web-app_2_3.dtd">- <web-app>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/acegi-config.XML</param-value>
- </context-param>
- <context-param>
- <param-name>Javax.faces.STATE_SAVING_METHOD</param-name>
- <param-value>server</param-value>
- </context-param>
- <context-param>
- <param-name>Javax.faces.CONFIG_FILES</param-name>
- <param-value>/WEB-INF/faces-config.XML</param-value>
- </context-param>
- <listener>
- <listener-class>
- org.springframework.web.context.ContextLoaderListener
- </listener-class>
- </listener>
- <listener>
- <listener-class>
- com.sun.faces.config.ConfigureListener
- </listener-class>
- </listener>
- <!-- Faces Servlet -->
- <servlet>
- <servlet-name>Faces Servlet</servlet-name>
- <servlet-class>Javax.faces.webapp.FacesServlet</servlet-class>
- <load-on-startup> 1 </load-on-startup>
- </servlet>
- <!-- Faces Servlet Mapping -->
- <servlet-mapping>
- <servlet-name>Faces Servlet</servlet-name>
- <url-pattern>*.faces</url-pattern>
- </servlet-mapping>
- <!-- Acegi filter configuration -->
- <filter>
- <filter-name>Acegi Filter Chain Proxy</filter-name>
- <filter-class>
- org.acegisecurity.util.FilterToBeanProxy
- </filter-class>
- <init-param>
- <param-name>targetClass</param-name>
- <param-value>
- org.acegisecurity.util.FilterChainProxy
- </param-value>
- </init-param>
- </filter>
- <!-- Acegi Filter Mapping -->
- <filter-mapping>
- <filter-name>Acegi Filter Chain Proxy</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </web-app>
注意,清單 1 包含以下標記:
◆3 個 <context-param> 標記
◆2 個 <listener> 標記
◆1 個 <filter> 標記
◆1 個 <servlet> 標記
◆1 個 <servlet-mapping> 標記
◆1 個 <filter-mapping> 標記
閱讀該文件,了解每個標記在 JSF-Acegi 應用程序中的用途。
向 Acegi和JSF 提供上下文參數
清單 1 中的每個
JSF 需要 javax.faces.STATE_SAVING_METHOD 和 javax.faces.CONFIG_FILES 參數。Javax.faces.STATE_SAVING_METHOD 參數指定希望在客戶機還是服務器上存儲 JSF 頁面-視圖狀態。Sun 的參考實現的默認行為是將 JSF 視圖存儲在服務器上。
Javax.faces.CONFIG_FILES 參數指定 JSF 需要的配置文件的位置。JSF 配置文件的詳細信息不屬於本文討論的范圍(參見 參考資料,獲取涉及該主題的資源鏈接)。
為 Acegi和JSF 配置偵聽器
現在看一下 清單 1 中的 2 個
◆啟動 JSP 或 servlet 應用程序時servlet容器創建一個新的 servlet 上下文。每當 JSP 或 servlet 應用程序啟動時,就會觸發此事件。
◆servlet 容器創建一個新的 servlet 請求對象。每當容器從客戶機收到一個 HTTP 請求時,此事件就會發生。
◆建立一個新的 HTTP 會話。當請求客戶機建立一個與 servlet 容器的會話時,此事件就會發生。
◆一個新屬性被添加到 servlet 上下文、servlet 請求和 HTTP 會話對象。
◆servlet 上下文、servlet 請求或 HTTP 會話對象的一個現有屬性被修改或刪除。
例如,Spring Framework 實現一個 Javax.servlet.ServletContextListener servlet 接口。實現此接口的 spring 類是 org.springframework.web.context.ContextLoaderListener。注意,這是 清單 1 的第一個
類似地,JSF 實現一個 com.sun.faces.config.ConfigureListener 類,該類實現一些事件-偵聽接口。可以在 清單 1 的第二個
本文稍後將解釋不同的事件-偵聽器接口,以及 Acegi和JSF 事件-偵聽器類內部執行的處理(請參閱 “啟動 JSF-Acegi 應用程序” 和 “處理對受 Acegi 保護的 JSF 頁面的請求”)。
配置和映射 servlet 過濾器
現在看一下 清單 1 中的
請注意 清單 1 中的
還需注意,清單 1 的
清單 1 中的
配置 JSF servlet
web.XML 文件中的
現在,您已經看到,web.xml 文件要部署 Acegi 以保護 JSF 應用程序所需的所有標記。您已經了解了偵聽器、過濾器和 servlet 如何相互協作。從這裡的討論中可以看出,如果在 servlet 容器中部署 清單 1 中的 web.XML 文件,Acegi和JSF 都試圖在兩種情形下進行一些處理:
◆當啟動應用程序時
◆當應用程序收到對 JSF 頁面的請求時