# 安全对象实现
# 安全拦截器
在 Spring Security2.0 之前,保护MethodInvocation
s 需要相当多的锅炉板配置。现在推荐的方法安全性是使用名称空间配置。通过这种方式,方法安全基础设施 bean 将自动为你配置,因此你实际上不需要了解实现类。我们将提供这里涉及的类的简要概述。
方法安全性是使用MethodSecurityInterceptor
来实现的,它保护MethodInvocation
s。根据配置方法,拦截器可以特定于单个 Bean 或在多个 bean 之间共享。拦截器使用MethodSecurityMetadataSource
实例来获得配置属性应用于特定方法调用。MapBasedMethodSecurityMetadataSource
用于存储由方法名(可以使用通配符)键控的配置属性,并且当在应用程序上下文中使用<intercept-methods>
或<protect-point>
元素定义属性时,将在内部使用。其他实现将用于处理基于注释的配置。
# 显式方法 SecurityInterceptor 配置
当然,你可以在应用程序上下文中直接配置MethodSecurityInterceptor
,以便与 Spring AOP 的代理机制之一一起使用:
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<sec:method-security-metadata-source>
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
</sec:method-security-metadata-source>
</property>
</bean>
# 安全拦截器
AspectJ 安全拦截器与上一节讨论的 AOP Alliance 安全拦截器非常相似。事实上,我们只在这一节讨论分歧。
AspectJ 拦截器被命名为AspectJSecurityInterceptor
。 AOP Alliance Security Interceptor 依赖 Spring 应用程序上下文通过代理在安全拦截器中进行编织,而AspectJSecurityInterceptor
则通过 AspectJ 编译器进行编织。在同一个应用程序中使用两种类型的安全拦截器并不少见,AspectJSecurityInterceptor
用于域对象实例安全,而 AOP AllianceMethodSecurityInterceptor
用于服务层安全。
让我们首先考虑在 Spring 应用程序上下文中如何配置AspectJSecurityInterceptor
:
<bean id="bankManagerSecurity" class=
"org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<sec:method-security-metadata-source>
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
</sec:method-security-metadata-source>
</property>
</bean>
正如你所看到的,除了类名,AspectJSecurityInterceptor
与 AOP Alliance Security Interceptor 完全相同。实际上,这两个拦截器可以共享相同的securityMetadataSource
,因为SecurityMetadataSource
处理java.lang.reflect.Method
s,而不是 AOP 库特定的类。当然,你的访问决策具有对相关 AOP 库特定调用的访问权限(即MethodInvocation
或JoinPoint
),因此在进行访问决策时可以考虑一系列附加条件(例如方法参数)。
接下来,你需要定义一个 AspectJaspect
。例如:
package org.springframework.security.samples.aspectj;
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
import org.springframework.beans.factory.InitializingBean;
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
private AspectJSecurityInterceptor securityInterceptor;
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
&& execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
Object around(): domainObjectInstanceExecution() {
if (this.securityInterceptor == null) {
return proceed();
}
AspectJCallback callback = new AspectJCallback() {
public Object proceedWithObject() {
return proceed();
}
};
return this.securityInterceptor.invoke(thisJoinPoint, callback);
}
public AspectJSecurityInterceptor getSecurityInterceptor() {
return securityInterceptor;
}
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null)
throw new IllegalArgumentException("securityInterceptor required");
}
}
}
在上面的示例中,安全拦截器将应用于PersistableEntity
的每个实例,这是一个未显示的抽象类(你可以使用任何其他类或你喜欢的pointcut
表达式)。对于那些好奇的人来说,AspectJCallback
是必要的,因为proceed();
语句只有在around()
正文中才具有特殊的含义。当它希望目标对象继续时,AspectJSecurityInterceptor
调用这个匿名的AspectJCallback
类。
你将需要配置 Spring 来加载该方面,并将其与AspectJSecurityInterceptor
连接。实现这一目标的 Bean 声明如下:
<bean id="domainObjectInstanceSecurityAspect"
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>
就是这样!现在,你可以在应用程序中的任何地方创建 bean,使用你认为合适的任何方法(例如new Person();
),并且它们将应用安全拦截器。
← 基于表达式的访问控制 方法安全性 →