Spring Security Config : AbstractInterceptUrlConfigurer

概述
介绍
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;
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值