领先一步
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> 或 @Secured("ROLE_ADMIN") public void foo() . . . }
同一用户应被授予访问相应业务功能保护的任何资源的权限。 <sec:authorize ifAllGranted="BF_POLICY_DELETE"> <p><a href="http://www.google.com">Google</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列表。例如:对于用户oleg,GrantedAuthorities列表应为: 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