搶先一步
VMware 提供培訓和認證,以加速您的進度。
了解更多這是我希望成為一系列小文章的第一部分,這些文章展示了圍繞 Spring Security 客製化的實際範例。這些客製化的需求並非憑空想像,而是全部來自實務經驗...
假設您有以下需求。 您有一個角色列表,其中每個角色都包含適用於該角色的業務功能列表(如下所示)
ROLE_ADMIN BF_QUOTE_CREATE BF_POLICY_CREATE BF_POLICY_DELETE
ROLE_AGENT BF_QUOTE_CREATE BF_POLICY_CREATE
ROLE_USER BF_QUOTE_CREATE
重點是能夠根據角色或業務功能來進行授權決策。
例如: 具有 ROLE_ADMIN 角色的使用者應被授予對受此角色保護的任何資源的訪問權限。 <sec:authorize ifAllGranted="ROLE_ADMIN"> <p><a href="http://www.google.com">Google</a> </sec:authorize>
or @Secured("ROLE_ADMIN") public void foo() . . . }
同樣地,該使用者也應被授予對受相應業務功能保護的任何資源的訪問權限。 <sec:authorize ifAllGranted="BF_POLICY_DELETE"> <p><a href="http://www.google.com">Google</a> </sec:authorize>
or @Secured("BF_POLICY_DELETE") public void foo() . . . }
實際上,有很多方法可以處理此需求。 其中一種方法是創建一個 RoleHierarchy 並使用 RoleHierarchyVoter 來遍歷角色層次結構。 這種方法的缺點是在 Spring Security 2.0.4 的目前實現中,taglibs (security: authorize . . . ) 不會通過 AccessDecisionManager 做出決策,因此在做出有關保護 HTML 元素的決策時,沒有 Voters 發揮任何作用。 但是,鑑於 Spring Security 驚人的靈活性和客製化能力,實現此需求仍然非常簡單。 Spring Security 的最大好處之一是圍繞如何創建 Principal(UserDetails 物件)的客製化。 創建 UserDetails 物件時,它會填充 GrantedAuthorities 列表。 此列表稍後會被檢查以匹配保護資源的 GrantedAuthority。 我們可以進行的客製化之一是在創建 UserDetails 物件期間客製化 GrantedAuthorities 列表。
在提供的範例中,有兩個屬性檔案(為了簡化,我使用屬性檔案,但是您可以輕鬆地修改它以使用 DB 或 LDAP)。 一個檔案 users.properties 將使用者映射到 roles oleg=powder,ROLE_ADMIN
,而另一個檔案 role-to-bf.properties 將 roles 映射到 business functions 列表 ROLE_ADMIN=BF_QUOTE_CREATE,BF_POLICY_CREATE,BF_POLICY_DELETE
我們的目標是創建一個 UserDetails 物件,該物件包含一個代表 roles 和 business functions 的 GrantedAuthorities 列表。 例如:對於使用者 oleg,GrantedAuthorities 列表應為: ROLE_ADMIN,BF_QUOTE_CREATE,BF_POLICY_CREATE,BF_POLICY_DELETE
因此,我們只需要定義一個 UserDetailsService 的自定義實現,通過使用兩個屬性檔案(在實際應用中可以是 DB 或 LDAP),我們將創建自定義的 GrantedAuthorities 列表,然後將它們注入到最終的 UserDetails 物件中。 這非常簡單,我們可以重複使用現有的 GrantedAuthority 介面實現,例如 GrantedAuthorityImpl。 但是,我們還希望確保我們可以追蹤(用於除錯或任何其他目的)每個代表業務功能的 GrantedAuthority 的 父 GrantedAuthority。 為了實現這兩個目標,我們將通過定義一個 BusinessFunctionGrantedAuthority 類來擴展 GrantedAuthorityImpl,該類僅包含定義此類 business function 的所有父 GrantedAuthority 物件的列表。 public class BusinessFunctionGrantedAuthority extends GrantedAuthorityImpl { private List<GrantedAuthority> parentAuthorities; . . . }
然後,我們將創建 UserDetailsService 的自定義實現,並實現 loadUserByName(..) 方法,我們將執行以下操作
1. 根據 users.properties 檔案的內容創建 UserAttribute 物件。 UserAttribute 將包含代表角色的 GrantedAuthorities 列表。
2. 遍歷 role-GratedAuthorities 列表,並為每個 role-GrantedAuthority 創建一個 BusinessFunctionGrantedAuthority 並將其添加到已創建的 GrantedAuthorities 的整體列表中
2.1 將父 GrantedAuthority 添加到每個 BusinessFunctionGrantedAuthority
3. 創建包含 GrantedAuthorities 完整列表的最終 UserDetails 物件。
然後在 Spring Security 配置中定義您的 AuthenticationProvider
注意:我們正在使用由 ComplexAuthorityUserDetailsService 類實現的自定義 UserDetailsService 注入 AuthenticationProvider。(有關更多詳細信息,請參閱範例程式碼)
保護您的資源,部署和存取應用程式:http://localhost:8080/spring-security-sample-grantedAuthority/index.jsp
登錄後,您應該看到 GrantedAuthorities 的列表以及 Principal 的其他屬性。
您可以清楚地看到,代表 business function 的 GrantedAuthority 也顯示了定義此類 business function 的父 GratedAuthorities 列表。 檢查 index.jsp 並觀察 security:authorize 標籤如何使用 roles 和 business functions 來保護 HTML 元素。 這就是全部。 您可以清楚地看到,通過一些小的客製化,您可以輕鬆地擴展和客製化 Principal 的結構,並根據自定義 GrantedAuthorities 應用聲明性保護,而無需使用自定義安全程式碼污染您的業務程式碼。
範例程式碼可以在此處下載: spring-security-sample-grantedauthority