SpringSecurity源码学习(五)

本文详细介绍了Spring Security中HttpSecurity的构建过程,包括触发机制、创建步骤及如何通过配置器定制化SecurityFilterChain。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

总结创建HttpSecuirty的创建过程,及其构建SecurityFilterChain过程。有和前面重复的地方,不管了…

触发HttpSecurity的创建过程

前面谈到,WebSecurity构建FilterChainProxy的过程中使用到了WebSecurityConfigurerAdapter的一个子类(这个子类一般需要用户定义的),调用了其init()。正是在这里,触发了HttpSecurity的构建过程。

    public void init(final WebSecurity web) throws Exception {
        //触发了HttpSecurity的构建
        final HttpSecurity http = getHttp();
        web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
            public void run() {
                FilterSecurityInterceptor securityInterceptor = http
                        .getSharedObject(FilterSecurityInterceptor.class);
                web.securityInterceptor(securityInterceptor);
            }
        });
    }

创建HttpSecurity

    protected final HttpSecurity getHttp() throws Exception {
        if (http != null) {
            return http;
        }

        DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
                .postProcess(new DefaultAuthenticationEventPublisher());
        /*
         *  localConfigureAuthenticationBldr=“本地的授权管理器构建器”,它是可以由用户配置的
         */
        localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
        /**
         *   此方法用于创建“授权管理器”,比较重要,下文单独介绍。
         *   使用“本地的授权管理器构建器”构建授权管理器
         */
        AuthenticationManager authenticationManager = authenticationManager();
        /**
         * authenticationBuilder=“默认的的授权管理器”,这个是框架提供的默认配置
         * 将使用本地配置构建的授权管理器,作为默认的授权管理器的父管理器
         */
        authenticationBuilder.parentAuthenticationManager(authenticationManager);
        /**
         *  参数一:后置处理器,前面说过很多次了
         *  参数二:授权管理器的构建器
         *  参数三:HttpSecurity是用于构建真正处理请求的SecurityFilterChian,它使用了很多配置
         *        器,这个配置器在创建的过程中可以共享一个对象(比如:ApplicationContext)。
         *        localConfigureAuthenticationBldr.getSharedObjects()用于获取用户自定义
         *        共享对象。
         */
        http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
                localConfigureAuthenticationBldr.getSharedObjects());
        /**
         *  设置共享对象。userDetailsService()方法后文详讨论。
         */
        http.setSharedObject(UserDetailsService.class, userDetailsService());
        http.setSharedObject(ApplicationContext.class, context);
        http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy);
        http.setSharedObject(AuthenticationTrustResolver.class, trustResolver);
        /**
         *  默认配置。
         *    1)、添加了n多SecurityFilterChian的构建器的配置器
         *    2)、直接添加了n多过滤器
         *  关于每个配置的作用,将单列一章讨论。
         */
        if (!disableDefaults) {
            http
                .csrf().and()
                .addFilter(new WebAsyncManagerIntegrationFilter())
                .exceptionHandling().and()
                .headers().and()
                .sessionManagement().and()
                .securityContext().and()
                .requestCache().and()
                .anonymous().and()
                .servletApi().and()
                .apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()
                .logout();
        }
        /**
         * 此方法被用户重写去修改默认配置。
         * 比如禁用csrf()、比如添加验证码校验、比如自定义权限认证 
         */
        configure(http);
        return http;
    }

使用本地配置构建授权管理器

    protected AuthenticationManager authenticationManager() throws Exception {
        if (!authenticationManagerInitialized) {
            /**
             * 这个方法由用户重写
             */
            configure(localConfigureAuthenticationBldr);
            /**
             *  如果用户对configure(AuthenticationManagerBuilder auth)方法进行了重写,
             * 那么,disableLocalConfigureAuthenticationBldr将为false,即:将使用用户的
             * 配置来构建“授权管理器”
             */
            if (disableLocalConfigureAuthenticationBldr) {
                authenticationManager = authenticationConfiguration
                        .getAuthenticationManager();
            }
            else {
                authenticationManager = localConfigureAuthenticationBldr.build();
            }
            authenticationManagerInitialized = true;
        }
        return authenticationManager;
    }

创建共享对象UserDetailsService

@EnableWebSecurity这个注解其实也被@EnableGlobalAuthentication注解修饰。它导入了一个关于认证的配置类:AuthenticationConfiguration。这个类中,向容器中创建了AuthenticationManagerBuilder。

    @Bean
    public AuthenticationManagerBuilder authenticationManagerBuilder(
            ObjectPostProcessor<Object> objectPostProcessor) {
        return new AuthenticationManagerBuilder(objectPostProcessor);
    }

为什么这么麻烦的获取UserDetailsService?

    protected UserDetailsService userDetailsService() {
        AuthenticationManagerBuilder globalAuthBuilder = context
                .getBean(AuthenticationManagerBuilder.class);
        return new UserDetailsServiceDelegator(Arrays.asList(
                localConfigureAuthenticationBldr, globalAuthBuilder));
    }

其实是SpringSecurity提供了两种设置UserDetailsService的方式

第一种:
@EnableWebSecurity
@ComponentScan("fn.wd.security")
public class SpringSecurityConfiger extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomUserDetailService customUserDetailService;

    @Autowired
    private AuthenticationManagerBuilder authenticationManagerBuilder;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          authenticationManagerBuilder.userDetailsService(customUserDetailService)
                  .passwordEncoder(standardPasswordEncoder());

    }
}
第二种:
@EnableWebSecurity
@ComponentScan("fn.wd.security")
public class SpringSecurityConfiger extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomUserDetailService customUserDetailService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.userDetailsService(customUserDetailService)
                  .passwordEncoder(standardPasswordEncoder());

    }
}

触发HttpSecurity的构建过程

HttpSecurity的构建过程是由WebSecurity构建具体的SecurityFilterChain时触发的:

    protected Filter performBuild() throws Exception {
        int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
        List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(
                chainSize);
        for (RequestMatcher ignoredRequest : ignoredRequests) {
            securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
        }
        for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
            //securityFilterChainBuilder.build()触发构建过程
            securityFilterChains.add(securityFilterChainBuilder.build());
        }
        FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
        if (httpFirewall != null) {
            filterChainProxy.setFirewall(httpFirewall);
        }
        filterChainProxy.afterPropertiesSet();

        Filter result = filterChainProxy;
        postBuildAction.run();
        return result;
    }

定义构建的模版

不要忘记HttpSecurity和WebSecurity一样,都是AbstractConfiguredSecurityBuilder的子类。AbstractConfiguredSecurityBuilder中定义了构建的模版:

    @Override
    protected final O doBuild() throws Exception {
        synchronized (configurers) {
            buildState = BuildState.INITIALIZING;

            beforeInit();
            init();//调用所有配置器的init()

            buildState = BuildState.CONFIGURING;

            beforeConfigure();
            configure();//调用所有配置器的configurer()

            buildState = BuildState.BUILDING;

            O result = performBuild();//最后调用HttpSecurity中performBuild的实现

            buildState = BuildState.BUILT;

            return result;
        }
    }

构建SecurityFilterChain

由于这个构建器(HttpSecurity)里面的构建器配置器很多,所以init()、configurer()会比较复杂,后面详讨论吧,这里重点看下HttpSecurity的performBuild():

    @Override
    protected DefaultSecurityFilterChain performBuild() throws Exception {
        //comparator其实就是FilterComparator的对象
        Collections.sort(filters, comparator);
        return new DefaultSecurityFilterChain(requestMatcher, filters);
    }

可以看到的是,HttpSecurity只是将配置器配置的结果(filters)按照某种规则(FilterComparator)排序。

FilterComparator内部其实已经定义了框架提供的过滤器的顺序。当我们向过滤器链中插入一个过滤器(比如:插入校验验证码的过滤器)时,不仅是将此过滤器添加到HttpSecurity的配置中,还修改了这个比较器。比如HttpSecurity的addFilterBefore()方法:

    public HttpSecurity addFilterBefore(Filter filter,
            Class<? extends Filter> beforeFilter) {
        //先修改比较器
        comparator.registerBefore(filter.getClass(), beforeFilter);
        //然后才添加到配置中
        return addFilter(filter);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值