对于最新的稳定版本,请使用 Spring Security 6.5.0! |
安全对象实现
AOP 联盟 (MethodInvocation) 安全拦截器
在 Spring Security 2.0 之前,保护MethodInvocation
需要相当多的样板配置。
现在,方法安全性的推荐方法是使用命名空间配置。
这样,系统会自动为您配置方法安全性基础结构 bean,因此您实际上不需要了解实现类。
我们只提供此处涉及的类的快速概述。
方法安全性是使用MethodSecurityInterceptor
,它保护MethodInvocation
s.
根据配置方法,拦截器可能特定于单个 bean 或在多个 bean 之间共享。
拦截器使用MethodSecurityMetadataSource
实例以获取适用于特定方法调用的配置属性。MapBasedMethodSecurityMetadataSource
用于存储以方法名称(可以是通配符)为键的配置属性,当在应用程序上下文中使用<intercept-methods>
或<protect-point>
元素。
其他 implementations 将用于处理基于 annotation 的配置。
显式 MethodSecurityInterceptor 配置
当然,您可以配置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 (JoinPoint) 安全拦截器
AspectJ 安全拦截器与上一节中讨论的 AOP Alliance 安全拦截器非常相似。 事实上,我们只会在本节中讨论差异。
AspectJ 拦截器被命名为AspectJSecurityInterceptor
.
与 AOP Alliance 安全拦截器不同,AOP Alliance 安全拦截器依赖于 Spring 应用程序上下文通过代理编织安全拦截器,AspectJSecurityInterceptor
是通过 AspectJ 编译器编织的。
在同一个应用程序中使用这两种类型的安全拦截器并不少见,其中AspectJSecurityInterceptor
用于域对象实例安全性和 AOP 联盟MethodSecurityInterceptor
用于服务层安全性。
我们首先考虑一下AspectJSecurityInterceptor
在 Spring 应用程序上下文中配置:
<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 安全拦截器完全相同。
事实上,这两个拦截器可以共享相同的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 来加载 aspect 并将其与AspectJSecurityInterceptor
.
实现此目的的 bean 声明如下所示:
<bean id="domainObjectInstanceSecurityAspect"
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>
就是这样!
现在,您可以从应用程序中的任何位置创建您的 bean,使用您认为合适的任何方式(例如new Person();
),并且他们将应用安全拦截器。