对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

AOP 联盟 (MethodInvocation) 安全拦截器

在 Spring Security 2.0 之前,保护 s 需要相当多的样板配置。 现在,方法安全性的推荐方法是使用命名空间配置。 这样,方法安全基础结构 Bean 就会自动为您配置,因此您实际上不需要了解实现类。 我们将仅简要概述此处涉及的类。MethodInvocationSpring中文文档

方法安全性是使用 来强制执行的,它保护 s。 根据配置方法的不同,拦截器可以特定于单个 Bean,也可以在多个 Bean 之间共享。 侦听器使用实例来获取应用于特定方法调用的配置属性。 用于存储按方法名称键控的配置属性(可以是通配符),当使用 OR 元素在应用程序上下文中定义属性时,将在内部使用。 其他实现将用于处理基于注释的配置。MethodSecurityInterceptorMethodInvocationMethodSecurityMetadataSourceMapBasedMethodSecurityMetadataSource<intercept-methods><protect-point>Spring中文文档

显式 MethodSecurityInterceptor 配置

当然,您可以直接在应用程序上下文中配置一个,以便与 Spring AOP 的代理机制之一一起使用:MethodSecurityInterceptorSpring中文文档

<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 联盟安全拦截器非常相似。 事实上,我们只会在本节中讨论差异。Spring中文文档

AspectJ 拦截器被命名为 。 与AOP联盟安全拦截器不同,AOP联盟安全拦截器依赖于Spring应用程序上下文通过代理编织安全拦截器,而AOP联盟安全拦截器是通过AspectJ编译器编织的。 在同一应用程序中使用两种类型的安全拦截器并不少见,其中用于域对象实例安全,而 AOP 联盟用于服务层安全。AspectJSecurityInterceptorAspectJSecurityInterceptorAspectJSecurityInterceptorMethodSecurityInterceptorSpring中文文档

让我们首先考虑一下在 Spring 应用程序上下文中是如何配置的:AspectJSecurityInterceptorSpring中文文档

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

如您所见,除了类名外,与AOP联盟安全拦截器完全相同。 事实上,这两个拦截器可以共享相同的 ,因为 s 而不是特定于 AOP 库的类。 当然,您的访问决策可以访问相关的 AOP 库特定调用(即 或),因此在做出访问决策时可以考虑一系列附加条件(例如方法参数)。AspectJSecurityInterceptorsecurityMetadataSourceSecurityMetadataSourcejava.lang.reflect.MethodMethodInvocationJoinPointSpring中文文档

接下来,您需要定义一个 AspectJ 。 例如:aspectSpring中文文档

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");
		}
	}
}

在上面的示例中,安全拦截器将应用于 的每个实例,这是一个未显示的抽象类(您可以使用您喜欢的任何其他类或表达式)。 对于那些好奇的人来说,是需要的,因为该声明仅在身体中具有特殊含义。 当它希望目标对象继续时,将调用此匿名类。PersistableEntitypointcutAspectJCallbackproceed();around()AspectJSecurityInterceptorAspectJCallbackSpring中文文档

您需要配置 Spring 以加载方面并将其与 . 实现此目的的 Bean 声明如下所示:AspectJSecurityInterceptorSpring中文文档

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

就是这样! 现在,您可以使用任何您认为合适的方式(例如)从应用程序中的任何位置创建 Bean,并且它们将应用安全拦截器。new Person();Spring中文文档