SpringSecurity源码学习(五)

来源:互联网 发布:国外域名商哪个便宜 编辑:程序博客网 时间:2024/06/10 00:30

前言

总结创建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);    }
0 0
原创粉丝点击