程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2EE >> 使用Acegi保護JSF應用程序

使用Acegi保護JSF應用程序

編輯:J2EE

如何使用 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 文件

  1. <?XML version="1.0"?>
  2. <!DOCTYPE web-app PUBLIC-//Sun Microsystems, Inc.//DTD
    Web Application 2.3//EN http://Java.sun.com/dtd/web-app_2_3.dtd">
  3. <web-app>
  4. <context-param>
  5. <param-name>contextConfigLocation</param-name>
  6. <param-value>/WEB-INF/acegi-config.XML</param-value>
  7. </context-param>
  8. <context-param>
  9. <param-name>Javax.faces.STATE_SAVING_METHOD</param-name>
  10. <param-value>server</param-value>
  11. </context-param>
  12. <context-param>
  13. <param-name>Javax.faces.CONFIG_FILES</param-name>
  14. <param-value>/WEB-INF/faces-config.XML</param-value>
  15. </context-param>
  16. <listener>
  17. <listener-class>
  18. org.springframework.web.context.ContextLoaderListener
  19. </listener-class>
  20. </listener>
  21. <listener>
  22. <listener-class>
  23. com.sun.faces.config.ConfigureListener
  24. </listener-class>
  25. </listener>
  26. <!-- Faces Servlet -->
  27. <servlet>
  28. <servlet-name>Faces Servlet</servlet-name>
  29. <servlet-class>Javax.faces.webapp.FacesServlet</servlet-class>
  30. <load-on-startup> 1 </load-on-startup>
  31. </servlet>
  32. <!-- Faces Servlet Mapping -->
  33. <servlet-mapping>
  34. <servlet-name>Faces Servlet</servlet-name>
  35. <url-pattern>*.faces</url-pattern>
  36. </servlet-mapping>
  37. <!-- Acegi filter configuration -->
  38. <filter>
  39. <filter-name>Acegi Filter Chain Proxy</filter-name>
  40. <filter-class>
  41. org.acegisecurity.util.FilterToBeanProxy
  42. </filter-class>
  43. <init-param>
  44. <param-name>targetClass</param-name>
  45. <param-value>
  46. org.acegisecurity.util.FilterChainProxy
  47. </param-value>
  48. </init-param>
  49. </filter>
  50. <!-- Acegi Filter Mapping -->
  51. <filter-mapping>
  52. <filter-name>Acegi Filter Chain Proxy</filter-name>
  53. <url-pattern>/*</url-pattern>
  54. </filter-mapping>
  55. </web-app>

注意,清單 1 包含以下標記:
◆3 個 <context-param> 標記
◆2 個 <listener> 標記
◆1 個 <filter> 標記
◆1 個 <servlet> 標記
◆1 個 <servlet-mapping> 標記
◆1 個 <filter-mapping> 標記

閱讀該文件,了解每個標記在 JSF-Acegi 應用程序中的用途。

向 Acegi和JSF 提供上下文參數

清單 1 中的每個 標記定義一個參數,供 Acegi 或 JSF 在啟動或執行期間使用。第一個參數 — contextConfigLocation — 定義 Acegi 的 XML 配置文件的位置。

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 應用程序啟動和執行期間發生的事件。例如:
◆啟動 JSP 或 servlet 應用程序時servlet容器創建一個新的 servlet 上下文。每當 JSP 或 servlet 應用程序啟動時,就會觸發此事件。
◆servlet 容器創建一個新的 servlet 請求對象。每當容器從客戶機收到一個 HTTP 請求時,此事件就會發生。
◆建立一個新的 HTTP 會話。當請求客戶機建立一個與 servlet 容器的會話時,此事件就會發生。
◆一個新屬性被添加到 servlet 上下文、servlet 請求和 HTTP 會話對象。
◆servlet 上下文、servlet 請求或 HTTP 會話對象的一個現有屬性被修改或刪除。

標記就像一種可擴展性機制,允許在 servlet 容器內部運行的應用程序協同某些事件進行處理。servlet 規范定義了偵聽器類為處理事件而實現的一些接口。

例如,Spring Framework 實現一個 Javax.servlet.ServletContextListener servlet 接口。實現此接口的 spring 類是 org.springframework.web.context.ContextLoaderListener。注意,這是 清單 1 的第一個 標記中的偵聽器類。

類似地,JSF 實現一個 com.sun.faces.config.ConfigureListener 類,該類實現一些事件-偵聽接口。可以在 清單 1 的第二個 標記中找到 ConfigureListener 類。

本文稍後將解釋不同的事件-偵聽器接口,以及 Acegi和JSF 事件-偵聽器類內部執行的處理(請參閱 “啟動 JSF-Acegi 應用程序” 和 “處理對受 Acegi 保護的 JSF 頁面的請求”)。

配置和映射 servlet 過濾器

現在看一下 清單 1 中的 標記。在請求的 servlet 處理傳入的請求之前,servlet 應用程序使用過濾器對其進行預處理。在請求執行之前,Acegi 使用 servlet 過濾器對用戶進行身份驗證。

請注意 清單 1 中的 標記,它的 子標記指定一個 org.acegisecurity.util.FilterToBeanProxy 類。FilterToBeanProxy 類是 Acegi 的一部分。此類實現一個 javax.servlet.Filter 接口,該接口是 servlet 應用程序的一部分。Javax.servlet.Filter 接口有一個 doFilter() 方法,servlet 容器在收到請求時調用該方法。

還需注意,清單 1 的 標記有另一個子標記 標記指定實例化 FilterToBeanProxy 類所需的參數。可以從 清單 1 中看出,FilterToBeanProxy 類只需要一個參數,該參數是 FilterChainProxy 類的一個對象。FilterChainProxy 類表示 第 1 部分 1 中討論的整個 Acegi 過濾器鏈(請參閱 “安全過濾器” 小節)。FilterToBeanProxy 類的 doFilter() 方法使用 FilterChainProxy 類執行 Acegi 的安全過濾器鏈。

清單 1 中的 標記指定調用 Acegi 的 FilterToBeanProxy 的請求 URL。我已經將所有的 JSF 頁面映射到 Acegi 的 FilterToBeanProxy。這意味著只要用戶試圖訪問 JSF 頁面,FilterChainProxy doFilter() 方法就會自動獲得控制權。

配置 JSF servlet

web.XML 文件中的 標記指定希望從特定 URl 調用的 servlet(在本例中是一個 JSF servlet)。 標記定義該 URL。幾乎所有的 JSP 或 servlet 應用程序都包含這兩個標記,所以無需再作討論(參見 參考資料,獲取討論 servlet 編程的資源鏈接)。

現在,您已經看到,web.xml 文件要部署 Acegi 以保護 JSF 應用程序所需的所有標記。您已經了解了偵聽器、過濾器和 servlet 如何相互協作。從這裡的討論中可以看出,如果在 servlet 容器中部署 清單 1 中的 web.XML 文件,Acegi和JSF 都試圖在兩種情形下進行一些處理:
◆當啟動應用程序時
◆當應用程序收到對 JSF 頁面的請求時

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved