Spring Security 自定義 (第一部分 - 自定義 UserDetails 或擴充套件 GrantedAuthority)

工程 | Oleg Zhurakousky | 2009 年 1 月 2 日 | ...

這是我希望成為一系列關於 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"&gt;Google&lt;/a> </sec:authorize> @Secured("ROLE_ADMIN") public void foo()     . . . }

同一使用者應被授予訪問相應業務功能保護的任何資源的許可權。 <sec:authorize ifAllGranted="BF_POLICY_DELETE">     <p><a href="http://www.google.com"&gt;Google&lt;/a> </sec:authorize> @Secured("BF_POLICY_DELETE") public void foo()     . . . }

實際上有幾種處理此需求的方法。其中一種是建立一個RoleHierarchy並使用RoleHierarchyVoter遍歷角色層次結構。這種方法的缺點是,在Spring Security 2.0.4的當前實現中,標籤庫(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將角色對映到業務功能列表 ROLE_ADMIN=BF_QUOTE_CREATE,BF_POLICY_CREATE,BF_POLICY_DELETE 。我們的目標是建立一個UserDetails物件,其中包含代表角色業務功能GrantedAuthorities列表。例如:對於使用者olegGrantedAuthorities列表應為: ROLE_ADMIN,BF_QUOTE_CREATE,BF_POLICY_CREATE,BF_POLICY_DELETE 因此,我們所需要做的就是定義UserDetailsService的自定義實現,其中透過使用這兩個屬性檔案(在現實生活中可以是DB或LDAP)我們將建立自定義的GrantedAuthorities列表,然後將它們注入到最終的UserDetails物件中。這相當簡單,我們可以重用GrantedAuthority介面的現有實現,例如GrantedAuthorityImpl。然而,我們還希望確保我們能夠追蹤(用於除錯或任何其他目的)每個代表業務功能的GrantedAuthority的GrantedAuthority。為了實現這兩個目標,我們將透過定義一個BusinessFunctionGrantedAuthority類來擴充套件GrantedAuthorityImpl,該類簡單地包含定義此類業務功能的所有父GrantedAuthority物件的列表。 public class BusinessFunctionGrantedAuthority extends GrantedAuthorityImpl {     private List<GrantedAuthority> parentAuthorities;         . . . }

然後我們將建立UserDetailsService的自定義實現並實現loadUserByName(..)方法,在該方法中我們將執行以下操作

1. 根據users.properties檔案的內容建立UserAttribute物件。UserAttribute將包含代表角色的GrantedAuthorities列表。
2. 迭代角色-GrantedAuthorities列表,併為每個角色-GrantedAuthority建立一個BusinessFunctionGrantedAuthority,並將其新增到已建立的GrantedAuthorities的總列表中
    2.1 將父GrantedAuthority新增到每個BusinessFunctionGrantedAuthority
3. 建立包含GrantedAuthorities完整列表的最終UserDetails物件。

然後在Spring Security配置中定義您的AuthenticationProvider

注意:我們正在將AuthenticationProvider與ComplexAuthorityUserDetailsService類實現的自定義UserDetailsService注入。(有關更多詳細資訊,請參閱示例程式碼)
保護您的資源,部署並訪問應用程式:https://:8080/spring-security-sample-grantedAuthority/index.jsp
登入後,您應該看到GrantedAuthorities列表以及Principal的其他屬性被顯示出來

您可以清楚地看到代表業務功能GrantedAuthority也顯示了定義此類業務功能的父GratedAuthorities列表。檢查index.jsp並觀察security:authorize標籤如何同時使用角色業務功能來保護HTML元素。僅此而已。您可以清楚地看到,透過一些小的定製,您可以輕鬆擴充套件和定製Principal的結構,並根據自定義GrantedAuthorities應用宣告式保護,而無需用自定義安全程式碼汙染您的業務程式碼。

示例程式碼可在此處下載:spring-security-sample-grantedauthority

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有