本文是描述Spring Boot 与Spring Security在web环境下相关的学习笔记,偏向于原理性质。
在Spring Boot下,它其中包含了security的自动配置是 SecurityAutoConfiguration和SecurityFilterAutoConfiguration
要使用Spring Securty,就会使用注解EnableWebSecurity 来开启安全控制,从这个注解的源码中,可以看到它import 了 WebSecurityConfiguration
Spring Security的入口过滤器是如何放入web容器的?
Spring Security是依赖Filter,而它的入口Filter是在SecurityFilterAutoConfiguration中使用DelegatingFilterProxyRegistrationBean 将
DelegatingFilterProxy 过滤器放入到web容器中并命名为springSecurityFilterChain
根据DelegatingFilterProxy的原理,那肯定存在一个springSecurityFilterChain的bean,这个bean是在WebSecurityConfiguration中定义注入的。
@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
}
Spring Security的系列过滤器是怎么加上的?
入口点实际是上面代码的 webSecurity.build() ,经过层层查看代码,可以看到最终调用的了一个init方法,即:org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#init
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
进入getHttp方法中,我们可以看到如下一段代码(仅截取了一部分):
if (!disableDefaults) {
// @formatter:off
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<>()).and()
.logout();
// @formatter:on
到这里就比较清晰了,它的这些默认加载的过滤器实际上是在这里配置的,并且这里还包含一个配置参数来控制disableDefaults
默认值为false。
对于刚接触的朋友们,我们可能有一个疑问:这不是调用了些方法吗,这与过滤器有什么关系呢? 带着疑问我们接着往下看
我们可以进入一个方法来具体看看,比如 csrf ,它返回的是CsrfConfigurer 也就是说它使用了该配置器,
然后进入CsrfConfigurer类的configure 方法,就可以看到它是使用了CsrfFilter 过滤器。
@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);
}
参考资料:
https://www.jianshu.com/p/d5ce890c67f7
https://www.jianshu.com/p/e21c436543af
https://blog.csdn.net/qq_35494808/article/details/81537415
https://blog.csdn.net/liushangzaibeijing/article/details/81220610