对于最新的稳定版本,请使用 Spring Security 6.4.1spring-doc.cadn.net.cn

安全对象实现

本节介绍 Spring Security 如何处理 Secure Object 实现。spring-doc.cadn.net.cn

AOP 联盟 (MethodInvocation) 安全拦截器

在 Spring Security 2.0 之前,保护MethodInvocation实例需要大量的样板配置。 现在,方法安全性的推荐方法是使用命名空间配置。 这样,系统会自动为您配置方法安全基础结构 bean,因此您无需了解实现类。 我们只提供此处涉及的类的快速概述。spring-doc.cadn.net.cn

方法安全性通过使用MethodSecurityInterceptor,它保护MethodInvocation实例。 根据配置方法,拦截器可能特定于单个 bean 或在多个 bean 之间共享。 拦截器使用MethodSecurityMetadataSource实例以获取适用于特定方法调用的配置属性。MapBasedMethodSecurityMetadataSource用于存储以方法名称(可以是通配符)为键的配置属性,当在应用程序上下文中使用<intercept-methods><protect-point>元素。 其他实现用于处理基于 Comments 的配置。spring-doc.cadn.net.cn

显式 MethodSecurityInterceptor 配置

您可以配置MethodSecurityInterceptor直接在你的应用程序上下文中与 Spring AOP 的代理机制之一一起使用:spring-doc.cadn.net.cn

<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 安全拦截器非常相似。 我们仅在本节中讨论差异。spring-doc.cadn.net.cn

AspectJ 拦截器被命名为AspectJSecurityInterceptor. 与 AOP Alliance 安全拦截器不同,AOP Alliance 安全拦截器依赖于 Spring 应用程序上下文通过代理来编织安全拦截器,AspectJSecurityInterceptor是通过 AspectJ 编译器编织的。 在同一个应用程序中使用这两种类型的安全拦截器并不少见,其中AspectJSecurityInterceptor用于域对象实例安全性和 AOP 联盟MethodSecurityInterceptor用于服务层安全性。spring-doc.cadn.net.cn

我们首先考虑AspectJSecurityInterceptor在 Spring 应用程序上下文中配置:spring-doc.cadn.net.cn

<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>

两个拦截器可以共享相同的securityMetadataSource,作为SecurityMetadataSource适用于java.lang.reflect.Method实例,而不是特定于 AOP 库的类。 您的访问决策可以访问相关的特定于 AOP 库的调用 (MethodInvocationJoinPoint),并且可以在做出访问决策时考虑一系列其他条件(例如方法参数)。spring-doc.cadn.net.cn

接下来,您需要定义一个 AspectJaspect,如下例所示:spring-doc.cadn.net.cn

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-doc.cadn.net.cn

您需要配置 Spring 来加载 aspect 并将其与AspectJSecurityInterceptor. 下面的示例展示了一个实现此目的的 bean 声明:spring-doc.cadn.net.cn

<bean id="domainObjectInstanceSecurityAspect"
	class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
	factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>

现在,您可以从应用程序中的任何位置创建您的 bean,使用您认为合适的任何方式(例如new Person();),并且他们应用了安全拦截器。spring-doc.cadn.net.cn