Spring Security系列-Spring Security生命周期之诞生

10 篇文章 0 订阅
4 篇文章 0 订阅

前言

接着上一篇,我们来谈谈WebSecurity的规则是如何从我们配置规则加入到整个SpringSecurity的认证链条的。

配置

回顾一下上一篇那个简单的WebSecurity配置

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
                .httpBasic();
        // @formatter:on
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // @formatter:off
        auth
            .inMemoryAuthentication()
                .withUser("admin")
                .password(passwordEncoder.encode("123456"))
                .authorities("admin");
        // @formatter:on
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/js/**", "/favicon.ico");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

配置方法

上面的三个config配置方法里,应用了许多配置项。
比如httpBasic()方法,从下面的源代码可以看出,它会实例化HttpBasicConfigurer类,并应用到HttpSecurity里。

public HttpBasicConfigurer<HttpSecurity> httpBasic() throws Exception {
	return getOrApply(new HttpBasicConfigurer<>());
}

又比如inMemoryAuthentication()方法。

public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
			throws Exception {
	return apply(new InMemoryUserDetailsManagerConfigurer<>());
}

无论是HttpBasicConfigurer还是InMemoryUserDetailsManagerConfigurer,都有同一个父类SecurityBuilder。

builder设计模式

SecurityBuilder类是一个建造者类,只有一个build方法。

public interface SecurityBuilder<O> {
	O build() throws Exception;
}

SecurityBuilder有众多继承类,下面展示了其中的一部分。
在这里插入图片描述
还记得上一篇setFilterChainProxySecurityConfigurer方法创建的webSeurity对象,它也继承SecurityBuilder类。当webSeurity.build()后,就会引发它下面所有的SecurityBuild继承类的调用build方法,如上面说到的HttpBasicConfigurer和InMemoryUserDetailsManagerConfigurer类。

诞生

开始进入主题,看看webSecurity.build()是怎么一步步应用我们的配置三个方法的。

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
	public Filter springSecurityFilterChain() throws Exception {
		boolean hasConfigurers = webSecurityConfigurers != null
				&& !webSecurityConfigurers.isEmpty();
		if (!hasConfigurers) {
			WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
					.postProcess(new WebSecurityConfigurerAdapter() {
					});
			webSecurity.apply(adapter);
		}
		return webSecurity.build();
	}

1. 三个自定义配置

1.1 configure(AuthenticationManagerBuilder auth)

先看看是如何一步步来到的configure(AuthenticationManagerBuilder auth)方法。
WebSecurity.build() ->
AbstractSecurityBuilder.build() ->
AbstractConfiguredSecurityBuilder.doBuild() ->
AbstractConfiguredSecurityBuilder.init()->
WebSecurityConfigurerAdapter.init(final WebSecurity web)->
WebSecurityConfigurerAdapter.getHttp()->
WebSecurityConfigurerAdapter.authenticationManager()->
自定义WebSecurityConfig->configure(AuthenticationManagerBuilder auth)

1.2 configure(HttpSecurity http)

然后是来到的configure(HttpSecurity http)方法。
WebSecurity.build() ->
AbstractSecurityBuilder.build() ->
AbstractConfiguredSecurityBuilder.doBuild() ->
AbstractConfiguredSecurityBuilder.init()->
WebSecurityConfigurerAdapter.init(final WebSecurity web)->
WebSecurityConfigurerAdapter.getHttp()->
自定义WebSecurityConfig->configure(HttpSecurity http)

1.3 configure(WebSecurity web)

最后是来到的configure(WebSecurity http)方法。
WebSecurity.build() ->
AbstractSecurityBuilder.build() ->
AbstractConfiguredSecurityBuilder.doBuild() ->
AbstractConfiguredSecurityBuilder.configure()->
自定义WebSecurityConfig->configure(WebSecurity web)

FilterChainProxy

在springSecurityFilterChain Bean的构建中,会调用下面的performBuild()方法。于是就创建了FilterChainProxy实例,并会添加我们自定义配置到securityFilterChains中。ignoredRequests就是我们配置configure(WebSecurity web)方法中的web.ignoring().antMatchers("/css/", "/js/", “/favicon.ico”);而securityFilterChainBuilders就是我们配置的configure(HttpSecurity http)。

protected Filter performBuild() throws Exception {
	int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
	List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
			chainSize);
	for (RequestMatcher ignoredRequest : ignoredRequests) {
		securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
	}
	for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
		securityFilterChains.add(securityFilterChainBuilder.build());
	}
	FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);

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

2. ignoredRequest

下图可以清楚的看到3个ignoredRequest
在这里插入图片描述

3. securityFilterChain

securityFilterChain情况就比较复杂了,会合并我们自定义配置和默认配置

3.1默认配置

在WebSecurity.build()方法被调用时,还有一段SpringSecurity设置默认配置的代码,如下

protected final HttpSecurity getHttp() throws Exception {
	...
	http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
			sharedObjects);
	if (!disableDefaults) {
		// @formatter:off
		http
			.csrf().and()                                       // 1
			.addFilter(new WebAsyncManagerIntegrationFilter())  // 2
			.exceptionHandling().and()                          // 3
			.headers().and()                                    // 4
			.sessionManagement().and()                          // 5
			.securityContext().and()                            // 6
			.requestCache().and()                               // 7
			.anonymous().and()                                  // 8
			.servletApi().and()                                 // 9
			.apply(new DefaultLoginPageConfigurer<>()).and()    //10
			.logout();                                          //11
		// @formatter:on
		...
	}
	configure(http);
	return http;
}

从上面SpringSecurity提供的默认配置可以看出,SpringSecurity默认地为我们添加了11个SecurityConfigurer和Filter。

3.2 SecurityConfigurer和Filter

以SpringSecurity提供的默认配置,csrf()方法为例。
首先,csrf()方法应用了一个CsrfConfigurer配置类,这个类继承自SecurityConfigurer

public final class HttpSecurity extends
	AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
	implements SecurityBuilder<DefaultSecurityFilterChain>,
	HttpSecurityBuilder<HttpSecurity> {
	...
	public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
		ApplicationContext context = getContext();
		return getOrApply(new CsrfConfigurer<>(context));
	}
	...
}		

接着,CsrfConfigurer实现了configure(H http)方法,此方法会实例化一个CsrfFilter。

public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
		extends AbstractHttpConfigurer<CsrfConfigurer<H>, H> {
	...
	@Override
	public void configure(H http) throws Exception {
		CsrfFilter filter = new CsrfFilter(this.csrfTokenRepository);
		RequestMatcher requireCsrfProtectionMatcher = getRequireCsrfProtectionMatcher();
		if (requireCsrfProtectionMatcher != null) {
			filter.setRequireCsrfProtectionMatcher(requireCsrfProtectionMatcher);
		}
		AccessDeniedHandler accessDeniedHandler = createAccessDeniedHandler(http);
		if (accessDeniedHandler != null) {
			filter.setAccessDeniedHandler(accessDeniedHandler);
		}
		LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
		if (logoutConfigurer != null) {
			logoutConfigurer
					.addLogoutHandler(new CsrfLogoutHandler(this.csrfTokenRepository));
		}
		SessionManagementConfigurer<H> sessionConfigurer = http
				.getConfigurer(SessionManagementConfigurer.class);
		if (sessionConfigurer != null) {
			sessionConfigurer.addSessionAuthenticationStrategy(
					new CsrfAuthenticationStrategy(this.csrfTokenRepository));
		}
		filter = postProcess(filter);
		http.addFilter(filter);
	}
	...
}

最终,这个Filter会被添加到到http,而这个http就是HttpSecurity类,是本篇在开头提到的getHttp()方法中实例出来的,同时也是我们的自定义配置类中可以看到的那个HttpSecurity http。

4. 最终产物

上篇提到的springSecurityFilterChain是一个Bean。如果按照我们自定义的配置,它会包括4个DefaultSecurityFilterChain。其中三个filterChain是我们配置的web.ignoring().antMatchers("/css/", "/js/", “/favicon.ico”),另外一个是我们配置的configure(HttpSecurity http)。HttpSecurity因为保留了SpringSecurity的默认配置,所以会有我们配置之外的默认配置。
在这里插入图片描述
从上图可以看出,每一个HttpRequest都会经过4个FilterChain。

总结

本篇介绍了springSecurityFilterChain的形成,它最终包含了4个filterChain。其中HttpSecurity生成的filterChainer,包含了多个filter。那么下篇再谈谈这些Filter是怎么帮助我们来拦截或者处理HttpRequest的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值