第 51 章 角色继承

有两种方式可以用来实现角色继承,一种是使用UserDetailsServiceWrapper在读取用户信息时,使用角色继承为用户赋予全部的权限,另一种是使用RoleHierarchyVoter在判断权限的时候,使用角色继承为生成继承的全部权限。

使用UserDetailsServiceWrapper的情况,加载用户信息的同时用户会获得所有权限,所以使用Acl的情况也不会出问题。使用RoleHierarchyVoter的情况,因为只会在每次校验权限时才会使用继承获得所有权限,所以使用Acl的时候就会出现缺少权限的情况。

51.1. 使用RoleHierarchyVoter

把RoleHierarchyVoter加入配置文件中的accessDecisionManager。

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
	<property name="allowIfAllAbstainDecisions" value="false"/>
	<property name="decisionVoters">
		<list>
			<ref bean="roleHierarchyVoter"/>
			<ref bean="authenticatedVoter"/>
		</list>
	</property>
</bean>

<bean id="roleHierarchyVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
    <constructor-arg ref="roleHierarchy"/>
</bean>

<bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter"/>

<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy" value="ROLE_ADMIN > ROLE_USER"/>
</bean>
        

然后在http中引用这个accessDecisionManager即可。

<http auto-config='true' access-decision-manager-ref='accessDecisionManager'>
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" access="ROLE_USER" />
</http>
        

51.2. 使用数据库实现RoleHierarchy

实现代码来自http://jira.springframework.org/browse/SEC-1071。源代码在http://forum.springsource.org/showthread.php?t=65515。这部分代码已经延迟到3.2.0实现了。

使用基于Dao的RoleHierarchy需要两部设置。

第一是在数据库中建立对应的表结构,并设置初始数据,数据库表结构如下所示:

CREATE MEMORY TABLE ROLE_HIERARCHIES(
    INCLUDINGROLE VARCHAR(50),
    INCLUDEDROLE VARCHAR(50)
);
        

includingrole表示继承了其他角色的角色。includedrole表示被继承的角色。如果我们希望设置ROLE_ADMIN继承ROLE_USER,只需要进行如下设置。

INSERT INTO ROLE_HIERARCHIES(INCLUDINGROLE,INCLUDEDROLE) VALUES('ROLE_ADMIN','ROLE_USER')
        

这样RoleHierarchyEntryDaoJdbc会读取数据库中的数据,将其组装成ROLE_ADMIN > ROLE_USER格式,再交给RoleHierarchyImpl进行分析,最终用于RoleHierarchyVoter完成角色继承的判断。

下面修改配置文件,将daoRoleHierarchy的bean设置到配置文件中。

<bean id="roleHierarchyVoter" class="org.springframework.security.vote.RoleHierarchyVoter">
    <constructor-arg ref="daoRoleHierarchy"/>
</bean>

<bean id="daoRoleHierarchy"
    class="org.springframework.security.userdetails.hierarchicalroles.RoleHierarchyImplDaoAware">
    <property name="_roleHierarchyEntryDao" ref="roleHierarchyEntryDaoJdbc"/>
</bean>

<bean id="roleHierarchyEntryDaoJdbc"
    class="org.springframework.security.userdetails.hierarchicalroles.RoleHierarchyEntryDaoJdbc">
    <property name="dataSource" ref="dataSource"/>
</bean>
        

这样就完成了使用数据库保存角色继承信息的功能。

实例见ch219。