Spring Security 3.0.0.M1 釋出

工程 | Luke Taylor | 2009年6月3日 | ...

我們很高興宣佈 Spring Security 3.0 的第一個里程碑版本現已可供下載。該版本也可以透過 Maven 里程碑倉庫獲取,地址是http://maven.springframework.org/milestone。與 Spring 3.0 一樣,這是第一個要求最低 JDK 1.5 才能執行的版本,同時也需要 Spring 3.0,因此如果您尚未在使用,應該獲取 Spring 3.0.0.M3 版本。那麼這個版本有什麼新內容和變化呢?

基於表示式的訪問控制

此版本首次包含了我們基於Spring-EL 的授權支援的預覽。您現在可以在方法註解和 Web 安全中使用表示式。與熟悉的屬性和基於投票器的機制相比,這開啟了許多新的可能性。一個簡單的例子可能是一個好的開始。這是一個用於 Web 應用程式的例子,使用了 security 名稱空間

  <http use-expressions="true">
     <intercept-url pattern="/secure/**" access="hasRole('ROLE_SUPERVISOR') and hasIpAddress('192.168.1.0/24')" />
     ...
  </http>;

內建的hasRole('ROLE_SUPERVISOR')表示式並不複雜——它只是檢查當前使用者的許可權列表,如果使用者具有指定的角色則返回 true。但我們添加了一個額外的表示式來指定發出請求的 IP 地址必須在子網/掩碼引數定義的範圍內。根據您的網路設定,這可能實用也可能不實用,但它說明了基於表示式的方法有多強大。以前包含在“access”XML 屬性中的安全屬性列表已被布林表示式取代。如果表示式求值為“true”,則授予訪問許可權。如果求值為“false”,則拒絕訪問許可權。

@Pre 和 @Post 註解

方法安全性比我們剛剛看到的 Web 請求的簡單允許或拒絕更復雜一些。為了更全面地支援在方法安全中使用表示式,我們引入了四個新的註解,這些註解可以包含在方法呼叫之前和之後應用的表示式屬性。要啟用它們的支援,可以在global-method-security名稱空間元素上新增一個新屬性

    <global-method-security pre-post-annotations="enabled"/>

最明顯有用的註解是@PreAuthorize,它控制方法是否實際可以被呼叫。例如(來自“Contacts”示例應用程式)


    @PreAuthorize("hasRole('ROLE_USER')")
    public void create(Contact contact);

,這意味著只有具有“ROLE_USER”角色的使用者才允許訪問。這裡沒什麼新東西。但如果是

  
    @PreAuthorize("hasPermission(#contact, 'admin')")
    public void deletePermission(Contact contact, Sid recipient, Permission permission);

這裡我們實際上是使用一個方法引數作為表示式的一部分來決定當前使用者是否對給定的聯絡人擁有“admin”許可權。hasPermission()表示式透過應用程式上下文連結到 Spring Security ACL 模組(請參見 Contacts 示例配置瞭解如何實現)。如果您的程式碼編譯時包含除錯資訊,您可以按名稱訪問任何方法引數作為表示式變數。Spring-EL 的任何功能都可以在表示式中使用,因此您也可以訪問引數的屬性。例如,如果您想讓某個特定方法只允許使用者名稱與聯絡人使用者名稱匹配的使用者訪問,您可以這樣寫


    @PreAuthorize("#contact.name == principal.name)")
    public void doSomething(Contact contact);

這裡我們正在訪問另一個內建表示式,即當前 Spring Security 的“principal”Authentication物件,該物件從安全上下文中獲取。您也可以直接訪問Authentication物件本身,使用表示式名稱“authentication”。授權也可以在方法呼叫發生後執行,使用@PostAuthorize註解。要訪問方法的返回值,請在表示式中使用內建名稱“returnObject”。

過濾

您可能已經知道,Spring Security 也支援對集合和陣列進行過濾,現在可以使用表示式來實現。這最常用於方法的返回值。例如
    
    @PreAuthorize("hasRole('ROLE_USER')")
    @PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')")
    public List getAll();

@PostFilter註解一起使用時,Spring Security 會遍歷返回的集合,並移除其中提供的表示式為 false 的任何元素。“filterObject”名稱指的是集合中的當前物件。您也可以在方法呼叫之前進行過濾,使用@PreFilter,儘管這可能是一個不太常見的需求。語法完全相同,但如果存在多個集合型別的引數,您需要使用此註解的“filterTarget”屬性按名稱選擇其中一個。

程式碼庫重組

在 3.0 之前的版本中,Spring Security 的大部分程式碼都包含在spring-security-corejar 包中。多年來,隨著更多功能的新增,跟蹤程式碼庫內部以及第三方庫的依賴關係變得越來越困難。例如,使用者很難確定核心 Maven pom.xml 中列出的哪些依賴項是框架內特定功能集所必需的。此外,最初的包結構和類名自該框架於 2003 年作為 Acegi Security 起源以來一直存在,當時只支援幾種基本的身份驗證機制。隨著程式碼量的增加和功能集的擴充套件,這種包結構已開始顯露其年代。
Spring Security 2.0.4 Package Structure

Spring Security 2.0.4 包結構

上圖展示了由 Structure101 生成的 2.0.4 版本中 core、core-tiger、cas-client 和 acl jar 包的高階包圖。您無需成為程式碼結構專家就能意識到這裡存在一些問題。包內部存在大量迴圈引用,並且沒有清晰的整體依賴結構。此外,還存在一些包跨 jar 邊界拆分的問題,這可能導致 OSGi 問題。這種程式碼結構的脆弱性可能會隨著 Spring Security 的演進而帶來維護負擔,因此我們決定在 3.0 版本中重組程式碼,為未來的開發提供一個穩定的基礎。讓我們來看看現在是如何組織的。

專案 Jar 包

我們做的第一件事是將核心拆分成幾個 jar 包。該spring-security-corejar 包現在只包含基本的身份驗證和訪問控制程式碼,並且更加清晰。例如,它不再依賴 LDAP 或 servlet API,並且現在有專門用於 Web 特定的程式碼和 LDAP 的獨立 jar 包。我們還將名稱空間解析程式碼拆分到另一個單獨的 jar 包中,因為它依賴於大多數其他 jar 包,並且不暴露任何您可能直接在應用程式中使用的公共 API。只有當您在應用程式上下文 XML 檔案中使用 Spring Security 名稱空間配置時,才需要使用它。主要的專案 jar 包如下表所示。
Jar 包名稱 描述 何時使用 根包
spring-security-core 核心身份驗證和訪問控制類及介面。遠端呼叫支援和基本資源供應 API。 使用 Spring Security 的任何應用程式都必需。支援獨立應用程式、遠端客戶端、方法(服務層)安全和 JDBC 使用者資源供應。 org.springframework.security.core, org.springframework.security.access, org.springframework.security.authentication, org.springframework.security.provisioning, org.springframework.security.remoting
spring-security-web 過濾器和其他 Web 安全基礎設施及相關程式碼。任何依賴於 servlet API 的內容。 如果您需要 Spring Security Web 身份驗證服務和基於 URL 的訪問控制 org.springframework.security.web
spring-security-config 名稱空間解析程式碼。 如果您正在使用 Spring Security XML 名稱空間。 org.springframework.security.config
spring-security-ldap LDAP 身份驗證和資源供應程式碼。 如果您需要使用 LDAP 身份驗證或管理 LDAP 使用者條目。 org.springframework.security.ldap
spring-security-acl 域物件 ACL 實現。 如果您需要在應用程式中對特定的域物件例項應用安全性。 org.springframework.security.acls
spring-security-cas-client Spring Security 的 CAS 客戶端整合。 如果您想將 Spring Security Web 身份驗證與 CAS 單點登入伺服器一起使用。 org.springframework.security.cas
spring-security-openid OpenID Web 身份驗證支援。 如果您需要針對外部 OpenID 伺服器進行使用者身份驗證。 org.springframework.security.openid
現在在 jar 包級別有了更清晰的關注點分離。例如,只有在編寫 Web 應用程式時才需要 Web jar 包(及其傳遞依賴)。這也使得程式碼更容易導航和理解。下面展示了構成與上述 2.0.4 版本相同的程式碼集的 Spring Security 3.0 jar 包之間的依賴關係
Spring Security 3.0 jars

Spring Security 3.0.0.M1 Jar 包依賴

包結構

這些 jar 包的包佈局如下圖所示。如您所見,不再存在任何迴圈引用,並且結構更加清晰。
Spring Security 3.0.0.M1 Package Structure

Spring Security 3.0.0.M1 包結構

core 包及其子包包含框架中使用的基本類和介面,核心 jar 包中的另外兩個主要包是 authenticationaccessaccess 包包含訪問控制/授權程式碼,例如 AccessDecisionManager 及相關的基於投票器的實現、攔截和方法安全基礎設施、註解類以及對 Spring Security 3.0 基於表示式的訪問控制的支援。authentication 包包含 AuthenticationManager 及相關類(例如身份驗證異常類)、簡單的基於 DAO 的身份驗證提供者和密碼編碼器。

其他雜項變更

重新命名類

程式碼庫中的一些類名也開始顯露其年代。例如,AbstractProcessingFilter現在是AbstractAuthenticationProcessingFilter,其最常見的具體子類AuthenticationProcessingFilter現在是UsernamePasswordAuthenticationProcessingFilter,因為框架中現在有許多處理身份驗證請求的過濾器。其對應的AuthenticationEntryPoint現在是LoginUrlAuthenticationEntryPoint。名稱模糊的ObjectDefinitionSource已重新命名為SecurityMetadataSource,以及AbstractSecurityInterceptor上的相應屬性也已類似重新命名。實現類和子介面也已類似重新命名。HttpSessionContextIntegrationFilter現在是SecurityContextPersistenceFilter,它具有一個可插拔的策略來控制如何儲存安全上下文——它不必儲存在HttpSession.

身份驗證成功或失敗時的重定向/轉發

另一個問題在於AbstractProcessingFilter是控制瀏覽器在身份驗證成功或失敗後重定向到何處的不同方式數量過多。之前混合使用了屬性和策略。在 Spring Security 3.0.0.M1 中,這些已被兩個獨立的策略取代,它們是AuthenticationSuccessHandlerAuthenticationFailureHandler,它們完全負責處理目標地址。檢視這些介面的 Javadoc 並檢視問題 SEC-745 以獲取更多資訊。

參考手冊和網站更新

顯然,3.0 參考手冊仍在進行中 :-),但我們已經進行了一些更新。名稱空間技術概述章節應提供對框架的合理概述。請隨時透過問題跟蹤器提交任何想法或補丁。當然,如果您發現任何錯誤,也請隨時提交。

專案網站也已更新。FAQ 添加了一些新問題,並且有一個新頁面包含演示影片和線上文章的連結。請檢視並告知我們您希望在那裡看到什麼(外部安全連結頁面已在計劃中)。

結論

Spring Security 3 仍有很多工作要做,但我們希望您能嘗試這個里程碑版本,並就新的表示式語言支援提供反饋。您可以在 Jira ChangeLog 中找到截至目前為止的完整變更列表,您還可以在那裡找到當前專案路線圖的連結。

社群論壇是提問關於使用 Spring Security 或發起關於新功能討論的最佳場所。另外,如果您發現任何問題,可以提交一個 Jira Issue

希望您喜歡使用 Spring Security

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱