保护方法调用
尽管Spring使用filter来保护web请求,但是Spring依然可以利用AOP来提供声明式的方法级别的安全保护。你可以创建一个Spring AOP代理来拦截方法调用并将其传递给一个安全拦截器。
·1. 创建一个安全切片
创建一个AOP切片的最简单方法是使用Spring的BeanNameAutoProxyCreator,然后列出你想要保护的bean即可。例如,假设你想要保护courseService和billingService bean:
<bean id=”autoProxyCreator”
class=”org.springframework.aop.framework.autoproxy.
BeanNameAutoProxyCreator”>
<property name=”interceptorNames”>
<list>
<value>securityInteceptor</value>
</list>
</property>
<property name=”beanNames”>
<list>
<value>courseService</value>
<value>billingService</value>
</list>
</property>
</bean>
其中的securityInterceptor bean配置如下:
<bean id=”securityInterceptor” class=”…MethodSecurityInterceptor”>
<property name=”authenticationManager”>
<ref bean=”authenticationManager” />
</property>
<property name=”accessDecisionManager” >
<ref bean=”accessDecisionManager” />
</property>
<property name=”objectDefinitionSource”>
<value>
com.springinaction.springtrainning.service.
CourseService.createCourse = ROLE_ADMIN
com.springinaction.springtrainning.service.
CourseService.enroll *= ROLE_ADMIN, ROLE_REGISTER
</value>
</property>
</bean>
MethodSecurityInterceptor对于方法调用的作用等同于FilterSecurityInterceptor对于servlet请求的作用。也就是说,它拦截调用并且协同身份验证管理器和访问决策管理器一起来确保调用方法合法。
注意,这里的authenticationManager和accessDecisionManager属性和FilterSecurityInterceptor的是一样的。
MethodSecurityInterceptor和FilterSecurityInterceptor一样也有一个objectDefinitionSource属性,但是配置方法有些不同。FilterSecurityInterceptor中是用URL模式来匹配权限,这里使用方法模式来匹配那些需要调用方法的权限。
上图就是一个方法模式。它包含了完整路径的类名和需要被保护的方法名。你可能需要在在方法模式的前后两端使用通配符来匹配多个方法。
当调用一个受保护方法时,MethodSecurityInterceptor会确定用户是否通过身份验证并且拥有足够权限调用该方法。如果有,程序继续;如果没有将会抛出AcegiSecurityException异常。如果用户没有通过身份验证则抛出AuthenticationException异常,如果用户没有足够权限则抛出AccessDeniedException异常。
AcegiSecurityException是一个未检查异常,调用代码可能捕获也可能忽略它。在Spring配置文件中编写方法的安全属性是声明方法层次安全的唯一方法。现在让我们来看看如何使用Jakarta Common Attributes来声明安全属性:
·2. 使用元数据保护方法
有了事务和处理器映射,你必须首先声明一个元数据实现来告诉Spring如何加载元数据。如果你以前没有添加过CommonAttribute bean,那么添加方法如下:
<bean id=”attributes”
Class=”org.springframework.metadata.commons.CommonsAttributes”/>
接下来,你必须声明一个对象定义源。前面我们曾经通过设置objectDefinitionSrouce属性定义过对象定义源。现在你可以在对象源代码中直接声明安全属性。Spring提供的MethodDefinitionAttributes就是一个对象定义源,它可以从受保护对象的元数据中获取安全属性。
<bean id=”objectDefinitionSource” class=”..MethodDefinitionAttributes”>
<property name=”attrbutes”><ref bean=”attributes”/></property>
</bean>
配置完objectDefinitionSource之后,我们把它引入到MethodSecurityInterceptor的objectDefinitionSource属性中:
<bean id=”securityInterceptor” class=”…MethodSecurityInterceptor”>
…
<property name=”objectDefinitionSource”>
<ref bean=”objectDefinitionSource”/>
</property>
</bean>
现在你可以编写安全属性的代码了。我们只要知道SecurityConfig就可以了。它将一个方法和一个权限绑定在一起。例如:
public void enrollStudentInCourse(Course course, Student student)
throws CourseException;
在enrollStudentInCourse方法上声明这些安全属性等价于配置objectDefinitionSource。