SpringBoot–Spring Security(一)
一、概述
源码基于SpringBoot 2.7.xx版本
官网:https://spring.io/projects/spring-security
1.1 自动装配概览
- SecurityAutoConfiguration
- DefaultAuthenticationEventPublisher
- SpringBootWebSecurityConfiguration
- @EnableWebSecurity
- WebSecurityConfiguration
- SpringWebMvcImportSelector
- OAuth2ImportSelector
- HttpSecurityConfiguration
- @EnableGlobalAuthentication
- AuthenticationConfiguration
- @EnableWebSecurity
- SecurityDataConfiguration
- UserDetailsServiceAutoConfiguration
- InMemoryUserDetailsManager
- SecurityFilterAutoConfiguration
- DelegatingFilterProxyRegistrationBean
- @EnableMethodSecurity
- MethodSecuritySelector
- PrePostMethodSecurityConfiguration
- SecuredMethodSecurityConfiguration
- Jsr250MethodSecurityConfiguration
- MethodSecuritySelector
二、自动装配详解
2.1 SecurityAutoConfiguration
- 注册 DefaultAuthenticationEventPublisher;
- 导入另外两个安全配置类SpringBootWebSecurityConfiguration、SecurityDataConfiguration
2.2 SpringBootWebSecurityConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
@Configuration(proxyBeanMethods = false)
// 条件一 classpath中存在 SecurityFilterChain.class, HttpSecurity.class
// 条件二 没有自定义 WebSecurityConfigurerAdapter.class, SecurityFilterChain.class
@ConditionalOnDefaultWebSecurity
static class SecurityFilterChainConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
// 默认情况下对所有请求进行权限控制
http.authorizeRequests().anyRequest().authenticated();
http.formLogin();
http.httpBasic();
return http.build();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnClass(EnableWebSecurity.class)
@EnableWebSecurity
static class WebSecurityEnablerConfiguration {
}
}
2.2.1 SecurityFilterChain
默认的SecurityFilterChain,对所有请求进行权限控制,默认配置引入条件
- classpath中存在 SecurityFilterChain.class, HttpSecurity.class
- 没有自定义 WebSecurityConfigurerAdapter.class, SecurityFilterChain.class
2.2.2 @EnableWebSecurity
导入了如下4个类:
- WebSecurityConfiguration
- SpringWebMvcImportSelector
- OAuth2ImportSelector
- HttpSecurityConfiguration
2.2.2.1 WebSecurityConfiguration
WebSecurity配置类,创建一个FilterChainProxy bean来对用户请求进行安全过滤,这个FilterChainProxy bean的
名称为springSecurityFilterChain,它也是一个Filter,最终会被作为DelegatingFilterProxy代理的对象放入Spring容器中。
/**
* WebSecurity 配置类 :
* 1. 使用一个 WebSecurity 对象基于安全配置创建一个 FilterChainProxy 对象来对用户请求进行安全过滤。
* 2. 也会暴露一些必要的 bean。
* 3. 如何定制 Spring security 的web 安全,也就是 WebSecurity 对象
* 3.1 提供一个配置类,实现了接口 WebSecurityConfigurer
* 3.2 或者创建一个WebSecurityCustomizer对象
* 该配置类的配置会在使用 @EnableWebSecurity 时应用到系统。
*/
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
// 是否启用了调试模式,来自注解 @EnableWebSecurity 的属性 debug,缺省值 false
private Boolean debugEnabled;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();
private ClassLoader beanClassLoader;
@Autowired(required = false)
private ObjectPostProcessor<Object> objectObjectPostProcessor;
@Bean
public static DelegatingApplicationListener delegatingApplicationListener() {
return new DelegatingApplicationListener();
}
// 定义一个表达式处理器bean,缺省为一个 DefaultWebSecurityExpressionHandler,
// 仅在 bean springSecurityFilterChain 实例化之后才能实例化
@Bean
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
return this.webSecurity.getExpressionHandler();
}
// 定义 FilterChainProxy , 名字为 springSecurityFilterChain
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
Assert.state(!(hasConfigurers && hasFilterChain),
"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
if (!hasConfigurers && !hasFilterChain) {
// 如果没有 webSecurityConfigurer, 则提供一个却省的
WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break;
}
}
}
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}
// 根据配置 webSecurityConfigurers或者缺省 WebSecurityConfigurerAdapter 构建
// FilterChainProxy 并返回,这是最终加入到Servlet容器的Filter chain 。
return this.webSecurity.build();
}
// 定义一个bean,是web调用权限评估器,用于判断一个用户是否可以访问某个URL,
// 对于 JSP tag 支持必要。仅在bean springSecurityFilterChain 被定义时才生效。
@Bean
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public WebInvocationPrivilegeEvaluator privilegeEvaluator() {
return this.webSecurity.getPrivilegeEvaluator();
}
// 注入webSecurityConfigurers
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
ConfigurableListableBeanFactory beanFactory) throws Exception {
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));