访问控制
身份验证只是Spring安全机制的第一步。配置完验证管理器之后,现在需要配置访问决策管理器(access decision manager)来确定用户是否拥有权限访问资源。访问决策管理器由org.acegisecurity.AccessDecisionManager接口定义。
public interface AccessDecisionManager {
public void decide(Authentication auth, Object object,
ConfigAttributeDefinition config)
throws AccessDeniedException, InsufficientAuthenticationException;
public boolean supports(ConfigAttribute attribute);
public boolean support(Class clazz);
}
supports方法根据给定的资源类和配置属性判断是否该资源是否可以被访问,而decide方法是真正的做决策的方法,如果没有返回异常则可以访问,否则不能访问。
1. 访问决策投票机制
决策管理器不会自己做决定来控制资源是否可以被访问。它总是让一个或多个对象来投票,然后它对投票进行统计然后做决定。Spring提供三个类AffirmativeBased,ConsensusBased和UnanimousBased,它们都实现了AccessDecisionManager接口。每一个都有自己的决策办法。配置方法如下:
<bean id=”accessDecisionManager” class=”…UnanimousBased”>
<property name=”decisionVoters”>
<list>
<ref bean=”roleVoter” />
</list>
</property>
</bean>
通过decisionVoters属性你可以向访问决策管理器提供投票者列表。上面的例子中只有一个voter。下面让我们来看看如何配置roleVoter。
2. 投票访问决策
一个访问决策投票者并不负责做决策,只是负责投票而已。它可以是实现了AccessDecisionVoter接口的任何一个对象。
public interface AccessDicisionVoter {
public static final int ACCESS_GRANTED = 1;
public static final int ACCESS_ABSTAIN = 0;
public static final int ACCESS_DENIED = -1;
public boolean supports(ConfigAttribute) attribute);
public boolean supports(Class clazz);
public int vote(Authentication auth, Object object,
ConfigAttributeDefinition config);
}
AccessDecisionVoter接口和AccessDecisionManager类似。最大的不同在于decide方法换成了vote方法并返回int类型。
一个voter有三种投票方式:
·ACCESS_GRANTED:允许访问资源
·ACCESS_DENIED:拒绝访问资源
·ACCESS_ABSTAIN:不参与投票
尽管你可以编写自己的AccessDecisionVoter实现,但Spring提供了RoleVoter类你可以自由使用。当资源配置属性表示一个角色(role),特别是当资源配置属性名以ROLE_开头时,这个类会进行决策投票。具体投票方式如下:RoleVoter会比较资源所有配置属性和用户权限,如果匹配返回ACCESS_GRANTED,否则返回ACCESS_DENIED。只有权限不是ROLE_开头,RoleVoter才会弃权。配置RoleVoter方法如下:
<bean id=”roleVoter” class=”…vote.RoleVoter” />
如前所述,ROLE_开头的属性对RoleVoter才有效。不过你可以指定其他的属性前缀,如:
<bean id=”roleVoter” class=”….RoleVoter”>
<property name=”rolePrefix” value=”GROUP_” />
</bean>
现在,RoleVoter就只会针对那些GROUP_开头的权限进行投票。
3. 弃权处理
默认情况下,如果所有voter都弃权,那么访问决策管理器会拒绝资源访问。不过你可以覆盖掉这条规则:
<bean id=”accessDecisionManager” class=”…UnanimousBased”>
<property name=”decisionVoters”>
<list>
<ref bean=”roleVoter” />
</list>
</property>
<property name=”allowIfAllAbstain” value=”true” />
</bean>
这样当所有voter都弃权,manager将批准资源被访问。