SpringSecurity源码之WebSecurity构建FilterChainProxy
主要参考了https://mp.weixin.qq.com/s/D0weIKPto4lcuwl9DQpmvQ。
SpringSecurity版本是2.7.9。将SpringBoot和SpringSecurity结合使用,SpringSecurity自动配置类是SecurityAutoConfiguration.class。
@AutoConfiguration
@ConditionalOnClass({DefaultAuthenticationEventPublisher.class})
@EnableConfigurationProperties({SecurityProperties.class})
@Import({SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class})
public class SecurityAutoConfiguration {
public SecurityAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean({AuthenticationEventPublisher.class})
public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
return new DefaultAuthenticationEventPublisher(publisher);
}
}
SecurityAutoConfiguration导入了SpringBootWebSecurityConfiguration配置类。
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
class SpringBootWebSecurityConfiguration {
SpringBootWebSecurityConfiguration() {
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingBean(
name = {"springSecurityFilterChain"}
)
@ConditionalOnClass({EnableWebSecurity.class})
@EnableWebSecurity
static class WebSecurityEnablerConfiguration {
WebSecurityEnablerConfiguration() {
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({WebInvocationPrivilegeEvaluator.class})
@ConditionalOnBean({WebInvocationPrivilegeEvaluator.class})
static class ErrorPageSecurityFilterConfiguration {
ErrorPageSecurityFilterConfiguration() {
}
@Bean
FilterRegistrationBean<ErrorPageSecurityFilter> errorPageSecurityFilter(ApplicationContext context) {
FilterRegistrationBean<ErrorPageSecurityFilter> registration = new FilterRegistrationBean(new ErrorPageSecurityFilter(context), new ServletRegistrationBean[0]);
registration.setDispatcherTypes(DispatcherType.ERROR, new DispatcherType[0]);
return registration;
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnDefaultWebSecurity
static class SecurityFilterChainConfiguration {
SecurityFilterChainConfiguration() {
}
@Bean
@Order(2147483642)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
http.formLogin();
http.httpBasic();
return (SecurityFilterChain)http.build();
}
}
}
SecurityFilterChainConfiguration是默认的SecurityFilterChain配置类。WebSecurityEnablerConfiguration类上@EnableWebSecurity做了自动化配置Security的主要工作。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, HttpSecurityConfiguration.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
@EnableWebSecurity注解导入了WebSecurityConfiguration配置类,同时引入了@EnableGlobalAuthentication注解。来看下WebSecurityConfiguration类。
WebSecurityConfiguration实现了ImportAware,BeanClassLoaderAware两个接口。BeanClassLoaderAware主要是为了获取ClassLoader。ImportAware的作用在松哥的博客说了。是为了获取到 @EnableWebSecurity中的属性值,这里主要是 debug 属性。WebSecurityConfiguration主要看springSecurityFilterChain(),setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor, ConfigurableListableBeanFactory beanFactory)方法。先看下setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor, ConfigurableListableBeanFactory beanFactory)。
@Autowired(
required = false
)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor, ConfigurableListableBeanFactory beanFactory) throws Exception {
this.webSecurity = (WebSecurity)objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled);
}
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = (new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory)).getWebSecurityConfigurers();
webSecurityConfigurers.sort(WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
Iterator var6;
SecurityConfigurer config;
for(var6 = webSecurityConfigurers.iterator(); var6.hasNext(); previousConfig = config) {
config = (SecurityConfigurer)var6.next();
Integer order = WebSecurityConfiguration.AnnotationAwareOrderComparator.lookupOrder(config);
if (previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
}
previousOrder = order;
}
var6 = webSecurityConfigurers.iterator();
while(var6.hasNext()) {
config = (SecurityConfigurer)var6.next();
this.webSecurity.apply(config);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
setFilterChainProxySecurityConfigurer方法主要做了以下几件事:
1、创建WebSecurity,并调用objectPostProcessor.postProcess将WebSecurity走了一遍Spring的创建bean流程。
2、获取SecurityConfigurer,SecurityConfigurer是为了配置SpringSecurity的类。并按照Order排序,校验了SecurityConfigurer集合之间的Order不能有相同的值。
3、将SecurityConfigurer集合加入到WebSecurity的configurers属性中,并将SecurityConfigurer集合设置到webSecurityConfigurers属性。
再来看springSecurityFilterChain()方法:
@Bean(
name = {"springSecurityFilterChain"}
)
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) {
WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
Iterator var7 = this.securityFilterChains.iterator();
while(true) {
while(var7.hasNext()) {
SecurityFilterChain securityFilterChain = (SecurityFilterChain)var7.next();
this.webSecurity.addSecurityFilterChainBuilder(() -> {
return securityFilterChain;
});
Iterator var5 = securityFilterChain.getFilters().iterator();
while(var5.hasNext()) {
Filter filter = (Filter)var5.next();
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor)filter);
break;
}
}
}
var7 = this.webSecurityCustomizers.iterator();
while(var7.hasNext()) {
WebSecurityCustomizer customizer = (WebSecurityCustomizer)var7.next();
customizer.customize(this.webSecurity);
}
return (Filter)this.webSecurity.build();
}
}
主要做了几件事:
1、判断是否存在自定义的SecurityConfigurer和SecurityFilterChain,不存在则创建一个WebSecurityConfigurerAdapter。
2、将已存在的SecurityFilterChain集合WebSecurity的securityFilterChainBuilders属性中
3、调用WebSecurityCustomizer的自定义方法自定义WebSecurity
4、调用webSecurity的build方法
webSecurity.build方法会调用到AbstractConfiguredSecurityBuilder#doBuild()方法:
protected final O doBuild() throws Exception {
synchronized(this.configurers) {
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
this.beforeInit();
this.init();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.CONFIGURING;
this.beforeConfigure();
this.configure();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILDING;
O result = this.performBuild();
this.buildState = AbstractConfiguredSecurityBuilder.BuildState.BUILT;
return result;
}
}
设置了构建的生命周期,调用了几个方法。主要看init(),configure(),performBuild()三个方法。
AbstractConfiguredSecurityBuilder#init()
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
Iterator var2 = configurers.iterator();
SecurityConfigurer configurer;
while(var2.hasNext()) {
configurer = (SecurityConfigurer)var2.next();
configurer.init(this);
}
var2 = this.configurersAddedInInitializing.iterator();
while(var2.hasNext()) {
configurer = (SecurityConfigurer)var2.next();
configurer.init(this);
}
}
获取SecurityConfigurer类并执行init方法。这里的SecurityConfigurer是WebSecurityConfigurerAdapter。
WebSecurityConfigurerAdapter#init(WebSecurity web)
public void init(WebSecurity web) throws Exception {
HttpSecurity http = this.getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = (FilterSecurityInterceptor)http.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
});
}
创建了HttpSecurity,并将HttpSecurity添加到WebSecurity的securityFilterChainBuilders属性。同时设置postBuildAction属性,postBuildAction是构建完后执行的操作。
WebSecurityConfigurerAdapter#getHttp()
protected final HttpSecurity getHttp() throws Exception {
if (this.http != null) {
return this.http;
} else {
AuthenticationEventPublisher eventPublisher = this.getAuthenticationEventPublisher();
this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
AuthenticationManager authenticationManager = this.authenticationManager();
this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
Map<Class<?>, Object> sharedObjects = this.createSharedObjects();
this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
if (!this.disableDefaults) {
this.applyDefaultConfiguration(this.http);
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
Iterator var6 = defaultHttpConfigurers.iterator();
while(var6.hasNext()) {
AbstractHttpConfigurer configurer = (AbstractHttpConfigurer)var6.next();
this.http.apply(configurer);
}
}
this.configure(this.http);
return this.http;
}
}
调用this.authenticationManager()构建了AuthenticationManager,createSharedObjects创建了共享对象,创建了HttpSecurity。调用applyDefaultConfiguration为HttpSecurity设置默认的配置。从Spring.factorys文件中加载AbstractHttpConfigurer并应用在HttpSecurity。最后调用configure(HttpSecurity http)。一般会重写configure(HttpSecurity http)方法自定义安全的配置。重写的配置会覆盖默认的配置。
createSharedObjects()
private Map<Class<?>, Object> createSharedObjects() {
Map<Class<?>, Object> sharedObjects = new HashMap();
sharedObjects.putAll(this.localConfigureAuthenticationBldr.getSharedObjects());
sharedObjects.put(UserDetailsService.class, this.userDetailsService());
sharedObjects.put(ApplicationContext.class, this.context);
sharedObjects.put(ContentNegotiationStrategy.class, this.contentNegotiationStrategy);
sharedObjects.put(AuthenticationTrustResolver.class, this.trustResolver);
return sharedObjects;
}
默认的DetailsService是UserDetailsServiceDelegator,AuthenticationTrustResolver是AuthenticationTrustResolverImpl。AuthenticationTrustResolver判断是否是匿名登录或是RememberMe登录。
applyDefaultConfiguration(HttpSecurity http)
private void applyDefaultConfiguration(HttpSecurity http) throws Exception {
http.csrf();
http.addFilter(new WebAsyncManagerIntegrationFilter());
http.exceptionHandling();
http.headers();
http.sessionManagement();
http.securityContext();
http.requestCache();
http.anonymous();
http.servletApi();
http.apply(new DefaultLoginPageConfigurer());
http.logout();
}
csrf()将CsrfConfigurer配置类加入到HttpSecurity的configurers属性中。exceptionHandling()方法加入了ExceptionHandlingConfigurer配置类。headers()加入了HeadersConfigurer配置类。sessionManagement()加入了SessionManagementConfigurer配置类。securityContext()加入了SecurityContextConfigurer配置类。requestCache()加入了RequestCacheConfigurer配置类。anonymous()加入了AnonymousConfigurer配置类。servletApi()加入了ServletApiConfigurer配置类。加入了DefaultLoginPageConfigurer配置类。logout()加入了LogoutConfigurer配置类。
configure()调用SecurityConfigurer集合的configure(WebSecurity web)方法。
performBuild()方法创建并配置FilterChainProxy:
protected Filter performBuild() throws Exception {
Assert.state(!this.securityFilterChainBuilders.isEmpty(), () -> {
return "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. Typically this is done by exposing a SecurityFilterChain bean. More advanced users can invoke " + WebSecurity.class.getSimpleName() + ".addSecurityFilterChainBuilder directly";
});
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList(chainSize);
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList();
Iterator var4 = this.ignoredRequests.iterator();
while(var4.hasNext()) {
RequestMatcher ignoredRequest = (RequestMatcher)var4.next();
this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest + ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest, new Filter[0]);
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries.add(this.getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
var4 = this.securityFilterChainBuilders.iterator();
while(var4.hasNext()) {
SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder = (SecurityBuilder)var4.next();
SecurityFilterChain securityFilterChain = (SecurityFilterChain)securityFilterChainBuilder.build();
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries.add(this.getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
if (this.privilegeEvaluator == null) {
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(requestMatcherPrivilegeEvaluatorsEntries);
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) {
filterChainProxy.setFirewall(this.httpFirewall);
}
if (this.requestRejectedHandler != null) {
filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
if (this.debugEnabled) {
this.logger.warn("\n\n********************************************************************\n********** Security debugging is enabled. *************\n********** This may include sensitive information. *************\n********** Do not use in a production system! *************\n********************************************************************\n\n");
result = new DebugFilter(filterChainProxy);
}
this.postBuildAction.run();
return (Filter)result;
}
ignoredRequests是不走Spring Security Filter过滤器的请求,securityFilterChainBuilders是走Spring Security Filter过滤器的请求。分别加入到SecurityFilterChain中。调用securityFilterChainBuilder.build()创建Spring Security 过滤器链SecurityFilterChain。再将所有的SecurityFilterChain加入到FilterChainProxy中。

浙公网安备 33010602011771号