Spring Security
Spring Security是一个提供身份验证、授权和防止常见攻击的框架。
启动过程
以与Spring Boot整合来介绍
- SecurityAutoConfiguration自动配置类
classpath路径中存在DefaultAuthenticationEventPublisher类时才加载,加载了一个DefaultAuthenticationEventPublisher类到容器中
导入SpringBootWebSecurityConfiguration(提供默认配置)、WebSecurityEnablerConfiguration(核心)和SecurityDataConfiguration配置类
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class,
SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {
@Bean
@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
return new DefaultAuthenticationEventPublisher(publisher);
}
}
- WebSecurityEnablerConfiguration
当不存在名为springSecurityFilterChain的bean时且Web类型为Servlet才加载
@EnableWebSecurity启用Web安全
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {
}
- @EnableWebSecurity
WebSecurityConfiguration配置类创建了一个名为springSecurityFilterChain的过滤器
@EnableGlobalAuthentication启用全局方法安全注解功能
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class,
OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
// 是否启用调试,默认false
boolean debug() default false;
}
- WebSecurityConfiguration
注册了AutowiredWebSecurityConfigurersIgnoreParents对象来从beanFactory中获得WebSecurityConfigurer类型的类
在初始化改类时调用setFilterChainProxySecurityConfigurer方法加载环境中的WebSecurityConfigurer,创建WebSecurity类
相关类理解
1.SecurityBuilder: build方法创建对象O
2.SecurityConfigurer<O, B extends SecurityBuilder>:构建者的配置器,用来配置Builder,首先调用init,再调用configure
3.SecurityConfigurerAdapter<O, B extends SecurityBuilder> implements SecurityConfigurer<O, B>:允许子类继承SecurityConfigurer中感兴趣的方法4.WebSecurityConfigurer<T extends SecurityBuilder> extends SecurityConfigurer<Filter, T>:用于定制WebSecurity
5.WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder:用来创建filter6.AbstractSecurityBuilder通过原子boolean类实现了线程安全
7.AbstractConfiguredSecurityBuilder定义了构建状态及过程
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
// 用来构建filter
private WebSecurity webSecurity;
// webSecurity的配置信息
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
}
Spring Security中filter的创建过程
- 自动配置中创建Filter(WebSecurityConfiguration)
public Filter springSecurityFilterChain() throws Exception {
// 判断当前ioc容器中是否存在WebSecurityConfigurer
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
// 不存在则使用默认的WebSecurityConfigurerAdapter来配置webSecurity
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
// 创建filter
return webSecurity.build();
}
- 调用AbstractSecurityBuilder的build方法,CAS判断调用AbstractConfiguredSecurityBuilder的dobuild方法
在默认的WebSecurityConfigurerAdapter中init方法初始了HttpSecurity和FilterSecurityInterceptor对象,configure方法为空
protected final O doBuild() throws Exception {
synchronized (configurers) {
// 初始状态
buildState = BuildState.INITIALIZING;
// 空方法
beforeInit();
// 调用WebSecurityConfigurer配置类的init方法配置webSecurity
init();
// 配置状态
buildState = BuildState.CONFIGURING;
// 在HttpSecurity中实现共享对象AuthenticationManager的构建
beforeConfigure();
// 调用WebSecurityConfigurer配置类的configure方法配置webSecurity
configure();
// 构建中
buildState = BuildState.BUILDING;
// 调用webSecurity的performBuild方法
O result = performBuild();
// 构建完成
buildState = BuildState.BUILT;
return result;
}
}
- 调用performBuild返回过滤器(WebSecurity)
securityFilterChainBuilders是在上一步的init中添加的
ignoredRequests在上一步的configure方法中添加
protected Filter performBuild() throws Exception {
···提示
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
// 创建SecurityFilterChain列表
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
// 添加DefaultSecurityFilterChain类型
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
// 添加SecurityFilterChain类型
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
// 生成过滤器链代理对象返回
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
···日志
// 空方法,用于在构建完成后执行
postBuildAction.run();
return result;
}
- 最终返回的过滤器FilterChainProxy(tomcat中的一个过滤器)
1.如果FilterChainProxy中的filterChains链没有与请求匹配的则调用下一个tomcat中的filter
2.创建VirtualFilterChain来执行在filterChains中第一个满足请求的SecurityFilterChian
public class FilterChainProxy extends GenericFilterBean {
// 持有的SecurityFilterChain,在上一步中传入构造函数注入
private List<SecurityFilterChain> filterChains;
// 防火墙
private HttpFirewall firewall = new StrictHttpFirewall();
}
private static class VirtualFilterChain implements FilterChain {
// tomcat中原始的过滤链
private final FilterChain originalChain;
// 匹配请求的SecurityFilter
private final List<Filter> additionalFilters;
// 当前请求
private final FirewalledRequest firewalledRequest;
// 当前过滤器个数
private final int size;
// 当前执行位置
private int currentPosition = 0;
}
HttpSecurity
作为Spring Boot中自动配置的SecurityFilterChain,当不做其他配置时FilterChainProxy只存在HttpSecurity过滤链。
初始化流程
- 在WebSecurity的init方法时调用WebSecurityConfigurerAdapter的init方法
public void init(final WebSecurity web) throws Exception {
// 创建HttpSecurity
final HttpSecurity http = getHttp();
// 将HttpSecurity添加到WebSecurity中,并添加创建完成后的Runnable
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
});
}
- getHttp方法(WebSecurityConfigurerAdapter)
相关类理解
AuthenticationManagerBuilder:创建AuthenticationManager的构造器
AuthenticationManager:处理身份验证请求,对用户的未授信凭据进行认证
Authentication:表示身份验证请求或身份验证主体在处理请求后的令牌
AuthenticationTrustResolver:用来评估身份验证令牌
protected final HttpSecurity getHttp() throws Exception {
// 如果存在直接返回
if (http != null) {
return http;
}
AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
// 放入UserDetailsService、
Map<Class<?>, Object> sharedObjects = createSharedObjects();
// 通过共享对象和身份验证构造器来创建HttpSecurity
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
sharedObjects);
// 如果启用默认配置,则添加一些默认的过滤器
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
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers =
SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
}
}
// 配置HttpSecurity
configure(http);
return http;
}
- configure方法(WebSecurityConfigurerAdapter)
protected void configure(HttpSecurity http) throws Exception {
// 添加两个配置类FormLoginConfigurer和ExpressionUrlAuthorizationConfigurer
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}