概述
介绍
AbstractInterceptUrlConfigurer是Spring Security Config的一个安全配置器抽象基类。它定义了为安全构建器HttpSecurity配置一个FilterSecurityInterceptor的安全配置器的通用行为逻辑。具体定义如下 :
安全配置器接口SecurityConfigurer约定的配置方法 configure
对目标安全构建器 http 进行配置,http 实际上可以理解成就是HttpSecurity。
主要就是调用当前类所定义的各种方法创建目标FilterSecurityInterceptor并设置到目标安全构建器http。
抽象方法 createMetadataSource
抽象方法,要求子类提供实现。用于创建安全元数据对象FilterInvocationSecurityMetadataSource,供目标安全拦截过滤器FilterSecurityInterceptor使用。
抽象方法 getDecisionVoters
抽象方法,要求子类提供实现。创建缺省AccessDecisionManager的方法createDefaultAccessDecisionManager会用到这个方法提供的一组AccessDecisionVoter。
私有方法 createDefaultAccessDecisionManager
创建目标FilterSecurityInterceptor用到的AccessDecisionManager可以由调用者设置,如果不设置,则使用该方法创建一个缺省的AccessDecisionManager,该缺省的AccessDecisionManager实现类使用AffirmativeBased,一票赞成即可通过。
私有方法 getAccessDecisionManager
该方法被configure用于获取最终用于目标FilterSecurityInterceptor要使用的AccessDecisionManager。如果调用者设置了当前安全配置器的AccessDecisionManager属性则使用它,否则使用createDefaultAccessDecisionManager创建一个缺省的AccessDecisionManager。
私有方法 createFilterSecurityInterceptor
创建createFilterSecurityInterceptor的具体过程方法。configure正式使用该方法创建FilterSecurityInterceptor,然后设置到目标安全构建器http。
内嵌静态类抽象类 AbstractInterceptUrlRegistry
该类继承自AbstractConfigAttributeRequestMatcherRegistry,表示一个URL pattern到所需的权限的映射表。这里每个映射项内部通过AbstractConfigAttributeRequestMatcherRegistry.UrlMapping来表示,其中URL pattern通过RequestMatcher来表示,所需要的权限通过ConfigAttribute集合来表示。该映射表是构建目标FilterSecurityInterceptor所要使用的安全元数据源SecurityMetadataSource对象的来源。
AbstractInterceptUrlRegistry也必须要由AbstractInterceptUrlConfigurer的具体实现子类提供自己的具体实现类。
继承关系
源代码
源代码版本 Spring Security Config 5.1.4.RELEASE
package org.springframework.security.config.annotation.web.configurers;
import java.util.List;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
/**
* A base class for configuring the FilterSecurityInterceptor.
*
*
* @param <C> the AbstractInterceptUrlConfigurer
* @param <H> the type of HttpSecurityBuilder that is being configured
*
* @author Rob Winch
* @since 3.2
* @see ExpressionUrlAuthorizationConfigurer
* @see UrlAuthorizationConfigurer
*/
abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>,
H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<C, H> {
private Boolean filterSecurityInterceptorOncePerRequest;
private AccessDecisionManager accessDecisionManager;
// 接口 SecurityConfigurer 定义的配置方法,对目标安全构建器 http 进行配置, http 实际上可以理解成就是
// HttpSecurity
@Override
public void configure(H http) throws Exception {
// 创建 FilterInvocationSecurityMetadataSource, FilterInvocationSecurityMetadataSource
// 是接下来创建 FilterSecurityInterceptor 所需要的, 在该类中,createMetadataSource方法
// 是一个抽象方法,也就是说,其实现逻辑必须有该类的实现子类提供。
FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
if (metadataSource == null) {
return;
}
// 创建 FilterSecurityInterceptor, 方法 createFilterSecurityInterceptor 的逻辑由本类提供,
// 并且被定义为 private,无需由子类覆盖,
// 这里创建 FilterSecurityInterceptor 使用到了 :
// 1. 目标安全构建器 http
// 2. 上面创建的安全元数据对象 metadataSource
// 3. 保存在目标安全构建器中的 AuthenticationManager 共享对象
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
http, metadataSource, http.getSharedObject(AuthenticationManager.class));
if (filterSecurityInterceptorOncePerRequest != null) {
securityInterceptor
.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
}
// 对新建安全拦截过滤器 FilterSecurityInterceptor 的后置处理
securityInterceptor = postProcess(securityInterceptor);
// 将新建的安全拦截过滤器 FilterSecurityInterceptor 添加到目标安全构建器 http 的Filter清单,
// 也添加为目标安全构建器的一个共享对象
http.addFilter(securityInterceptor);
http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
}
/**
* Subclasses should implement this method to provide a
* FilterInvocationSecurityMetadataSource for the
* FilterSecurityInterceptor.
*
* @param http the builder to use
*
* @return the FilterInvocationSecurityMetadataSource to set on the
* FilterSecurityInterceptor. Cannot be null.
*/
abstract FilterInvocationSecurityMetadataSource createMetadataSource(H http);
/**
* Subclasses should implement this method to provide the AccessDecisionVoter
* instances used to create the default AccessDecisionManager
*
* @param http the builder to use
*
* @return the AccessDecisionVoter instances used to create the default
* {@link AccessDecisionManager}
*/
abstract List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http);
abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T>
extends AbstractConfigAttributeRequestMatcherRegistry<T> {
/**
* Allows setting the AccessDecisionManager. If none is provided, a
* default AccessDecisionManager is created.
*
* @param accessDecisionManager the AccessDecisionManager to use
* @return the AbstractInterceptUrlConfigurer for further customization
*/
public R accessDecisionManager(AccessDecisionManager accessDecisionManager) {
AbstractInterceptUrlConfigurer.this.accessDecisionManager = accessDecisionManager;
return getSelf();
}
/**
* Allows setting if the FilterSecurityInterceptor should be only applied
* once per request (i.e. if the filter intercepts on a forward, should it be
* applied again).
*
* @param filterSecurityInterceptorOncePerRequest if the
* FilterSecurityInterceptor should be only applied once per request
* @return the AbstractInterceptUrlConfigurer for further customization
*/
public R filterSecurityInterceptorOncePerRequest(
boolean filterSecurityInterceptorOncePerRequest) {
AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest =
filterSecurityInterceptorOncePerRequest;
return getSelf();
}
/**
* Returns a reference to the current object with a single suppression of the type
*
* @return a reference to the current object
*/
@SuppressWarnings("unchecked")
private R getSelf() {
return (R) this;
}
}
/**
* Creates the default AccessDecisionManager
* @return the default AccessDecisionManager
*/
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
// 创建缺省使用的 AccessDecisionManager, 注意该缺省 AccessDecisionManager
// 是一个 AffirmativeBased, 也就是只要有一票赞成即通过
AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
return postProcess(result);
}
/**
* If currently null, creates a default AccessDecisionManager using
* #createDefaultAccessDecisionManager(HttpSecurityBuilder). Otherwise returns the
* AccessDecisionManager.
*
* @param http the builder to use
*
* @return the AccessDecisionManager to use
*/
private AccessDecisionManager getAccessDecisionManager(H http) {
// 获取配置过程最终要使用的 AccessDecisionManager, 该 AccessDecisionManager
// 可以由调用者指定,如果不指定,则使用缺省值,一个 AffirmativeBased:一票赞成即通过
if (accessDecisionManager == null) {
accessDecisionManager = createDefaultAccessDecisionManager(http);
}
return accessDecisionManager;
}
/**
* Creates the FilterSecurityInterceptor
*
* @param http the builder to use
* @param metadataSource the FilterInvocationSecurityMetadataSource to use
* @param authenticationManager the AuthenticationManager to use
* @return the FilterSecurityInterceptor
* @throws Exception
*/
private FilterSecurityInterceptor createFilterSecurityInterceptor(H http,
FilterInvocationSecurityMetadataSource metadataSource,
AuthenticationManager authenticationManager) throws Exception {
// 创建最终要配置到安全构建器 http 的安全拦截过滤器 FilterSecurityInterceptor,
// 所需要的各种属性都由该类定义的方法提供,这些方法有的由本类提供实现,有的需要由
// 实现子类提供实现。
FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
securityInterceptor.setSecurityMetadataSource(metadataSource);
securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));
securityInterceptor.setAuthenticationManager(authenticationManager);
securityInterceptor.afterPropertiesSet();
return securityInterceptor;
}
}