spring security 源码学习(四)SecurityFilterChain

SecurityFilterChain是Spring security真正执行认证授权的类。这个类初始化是从HttpSecurity的build而来。也就是上篇文章securityFilterChainBuilder.build()处得来。为了省去翻到上一篇文章,我把必要的代码和类图传送过来。

    for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
      securityFilterChains.add(securityFilterChainBuilder.build());(1)
    }

  

 

 

 所以securityFilterChainBuilder.build()就是AbstractSecurityBuilder的build方法

	public final O build() throws Exception {
		if (this.building.compareAndSet(false, true)) {
			this.object = doBuild();
			return this.object;
		}
		throw new AlreadyBuiltException("This object has already been built");
	}

  doBuild()就是我们的老演员了,上篇文章也说过的模版方法

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

			beforeInit();
			init();

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
			configure();

			buildState = BuildState.BUILDING;

			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}

  同样的,让我们从init()开始

	private void init() throws Exception {
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.init((B) this);
		}

		for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
			configurer.init((B) this);
		}
	}

  这里的getConfigurers()是从哪来的呢?答案就在Httpsecurity初始化的时候,同样,我们把上一篇文章中getHttp()方法考过来。

protected final HttpSecurity getHttp() throws Exception {
    if (http != null) {
        return http;
    }
 
    DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
            .postProcess(new DefaultAuthenticationEventPublisher());
    localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
 
    AuthenticationManager authenticationManager = authenticationManager();(1)
    authenticationBuilder.parentAuthenticationManager(authenticationManager);
    Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
 
    http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
            sharedObjects);(2)
    if (!disableDefaults) {
        // @formatter:off
        http
            .csrf().and()(3)
            .addFilter(new WebAsyncManagerIntegrationFilter())(4)
            .exceptionHandling().and()(5)
            .headers().and()(6)
            .sessionManagement().and()(7)
            .securityContext().and()(8)
            .requestCache().and()(9)
            .anonymous().and()(10)
            .servletApi().and()(11)
            .apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and()(12)
            .logout();(13)
        // @formatter:on
        ClassLoader classLoader = this.context.getClassLoader();
        List<AbstractHttpConfigurer> defaultHttpConfigurers =
                SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
 
        for(AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
            http.apply(configurer);
        }
    }
    configure(http);
    return http;
}

  我们拿其中一个来看看。就拿开头的http.csrf();

	public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
		ApplicationContext context = getContext();
		return getOrApply(new CsrfConfigurer<HttpSecurity>(context));
	}

 

	private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(
			C configurer) throws Exception {
		C existingConfig = (C) getConfigurer(configurer.getClass());
		if (existingConfig != null) {
			return existingConfig;
		}
		return apply(configurer);
	}

  

	public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
			throws Exception {
		configurer.addObjectPostProcessor(objectPostProcessor);
		configurer.setBuilder((B) this);
		add(configurer);
		return configurer;
	}

  

	private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {
		Assert.notNull(configurer, "configurer cannot be null");

		Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
				.getClass();
		synchronized (configurers) {
			if (buildState.isConfigured()) {
				throw new IllegalStateException("Cannot apply " + configurer
						+ " to already built object");
			}
			List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
					.get(clazz) : null;
			if (configs == null) {
				configs = new ArrayList<SecurityConfigurer<O, B>>(1);
			}
			configs.add(configurer);
			this.configurers.put(clazz, configs);
			if (buildState.isInitializing()) {
				this.configurersAddedInInitializing.add(configurer);
			}
		}
	}

  从上面的一连串的方法可以看出来,http.csrf()将new出来的CsrfConfigurer<HttpSecurity>(context)加入到了

private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();

  也就是加入到了getConfigurers返回的List中。

这里每个Configurer实际的init和config我们针对每个不同的Configurer都做一个专题走访,这里提供传送门

configure filter 简述
SecurityContextConfigurer
SecurityContextPersistenceFilter
 
     
     
     
     
     
     
     
     
     
     

最后我们看下performBuild方法

	@Override
	protected DefaultSecurityFilterChain performBuild() throws Exception {
		Collections.sort(filters, comparator);
		return new DefaultSecurityFilterChain(requestMatcher, filters);
	}

  这里倒是比较简单,对上面的filters拍了个序,然后new出了DefaultSecurityFilterChain,这里注意下DefaultSecurityFilterChain构造器的两个参数

	public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
		logger.info("Creating filter chain: " + requestMatcher + ", " + filters);
		this.requestMatcher = requestMatcher;
		this.filters = new ArrayList<Filter>(filters);
	}

  List<Filter> filters我们在上面已经分析过了,他们具体的形成我们后面细说,RequestMatcher requestMatcher这个参数的作用也是异常的大,他根据uri进行match判断,觉得了是否用这个HttpSecurity形成的FilterChain来对请求做处理。默认情况是

	private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;

  也就是所有的我们都走认证,如果想要做配置,就可以在上一篇文章中讲的在配置中override这个方法

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .antMatchers("/aaa").authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }

  

posted on 2021-12-22 23:42  幽人月  阅读(659)  评论(1编辑  收藏  举报