Default Spring Security rough start process source code analysis
Understand the basic process
understand firstspring.factories
spring.factories
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
- SecurityAutoConfiguration is the main configuration class, we mainly explain this class
- UserDetailsServiceAutoConfiguration is used to set the default password, which will be configured when SecurityAutoConfiguration configures HttpSecurity, so we won't go into details
- SecurityFilterAutoConfiguration does not speak
- The latter two are OAuth security, not to mention
We mainly analyze SecurityAutoConfiguration
that it is an automatic configuration class, affected by it EnableWebSecurit
, it will be imported HttpSecurityConfiguration
and loaded before loadingWebSecurityConfiguration
Their order of action is: HttpSecurityConfiguration
configuration HttpSecurityConfiguration
, WebSecurityConfiguration
configurationWebSecurity
The process is also mainly around: configuration HttpSecurity
--> configure the default basic SecurityFilterChain
--> configure WebSecurity
--> configure the finalSecurityFilterChain
It can also be understood as: how to create the final one SecurityFilterChain
?
EnableWebSecurity and EnableGlobalAuthentication annotations
@Import({
WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
}
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}
configurationHttpSecurity
From HttpSecurityConfiguration
the beginning, this class is the basic configuration class of HttpSecurity, the configuration is as follows:
HttpSecurityConfiguration.java
@Autowired
void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}//1
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
this.context);//2
AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);//3
authenticationBuilder.parentAuthenticationManager(authenticationManager());//4
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());//5
http
.csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
.securityContext(withDefaults())
.requestCache(withDefaults())
.anonymous(withDefaults())
.servletApi(withDefaults())
.apply(new DefaultLoginPageConfigurer<>());
http.logout(withDefaults());//6
return http;
}
Dependency injection of an AuthenticationConfiguration, pre-loading the AuthenticationConfiguration that needs to be automatically configured earlier,
This class creates three important Bean objects AuthenticationManagerBuild, InitializeUserDetailsBeanManagerConfigurer and InitializeAuthenticationProviderBeanManagerConfigurer
used respectively
- Build the AuthenticationManager
- Used to initialize UserDetailsServiceAutoConfiguration in spring.factories, its function is to provide default username and password,
- Initialize the user authentication manager (ProviderManager)
Create a lazy password loader
Create an authentication manager builder
Build an authentication manager
AuthenticationConfiguration.java
public AuthenticationManager getAuthenticationManager() throws Exception { //... for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) { authBuilder.apply(config); }//1 this.authenticationManager = authBuilder.build();//2 //... return this.authenticationManager; }
The builder uses the global authentication configuration, which is mentioned earlier when creating AuthenticationConfiguration
Build the authentication manager
Look directly at the last doBuild()
AbstractConfiguredSecurityBuilder
protected final O doBuild() throws Exception { synchronized (this.configurers) { this.buildState = BuildState.INITIALIZING; beforeInit();//1 init();//2 this.buildState = BuildState.CONFIGURING; beforeConfigure();//3 configure();//4 this.buildState = BuildState.BUILDING; O result = performBuild();//5 this.buildState = BuildState.BUILT; return result; } }
Operation before initialization
Initialize the configurator
Operation before configuration
Configure the configurator. There are many configurators, so I won’t talk about it. The configuration process is as follows:
AbstractConfiguredSecurityBuilder
private void configure() throws Exception { Collection<SecurityConfigurer<O, B>> configurers = getConfigurers(); for (SecurityConfigurer<O, B> configurer : configurers) { configurer.configure((B) this); } }
start building
This method creates and returns a PrivideManager
AuthenticationManagerBuilder.java
protected ProviderManager performBuild() throws Exception { ProviderManager providerManager = new ProviderManager(this.authenticationProviders, this.parentAuthenticationManager); return providerManager; }
Create , inject the
HttpSecurity
previousPrivider
HttpSecurity
HttpSecurity
Configure the basic configurator
configurationSecurityFilterChain
After the default HttpSecurity
configuration is complete, it will start to configure the default SecurityFilterChain
,
Let's look at the SecurityAutoConfiguration
imported SpringBootWebSecurityConfiguration
classes
SpringBootWebSecurityConfiguration.java
@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity//1
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
return http.build();//2
}
}
This class will only be configured when the default WebSecurity is met, as follows:
@Conditional(DefaultWebSecurityCondition.class)//1 public @interface ConditionalOnDefaultWebSecurity { } class DefaultWebSecurityCondition extends AllNestedConditions { DefaultWebSecurityCondition() { super(ConfigurationPhase.REGISTER_BEAN);} @ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class }) static class Classes { }//2 @ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class }) static class Beans { }//3 }
- meet
DefaultWebSecurityCondition
the conditions- Satisfied with
SecurityFilterChain.class
,HttpSecurity.class
two classes- Meet the lack
WebSecurityConfigurerAdapter.class
ofSecurityFilterChain.class
two beans, and the default Security configuration is missing these two classesCreate the default basic SecurityFilterChain, where the SecurityFilterChain has fifteen basic Filters:
configurationWebSecurity
After configuring the default basic SecurityFilterChain, it will be configuredWebSecurity
we see WebSecurityConfiguration
class
First look at how it is configured WebSecurity
, as follows:
WebrSecurityConfiguration.java
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)//1
throws Exception {
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);//2
Integer previousOrder = null;
Object previousConfig = null;
for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
previousOrder = order;
previousConfig = config;
}//3
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
this.webSecurity.apply(webSecurityConfigurer);
}//4
this.webSecurityConfigurers = webSecurityConfigurers;
}
- First look at the formal parameters with annotations
@Value
. This annotation gets all the previously configuredWebSeucurityConfigurer
(that is, customizedWebSecurityConfigurer
), and it will pass all the configurators to the currently created ones belowWebSecurity
.- create
WebSecurity
- Sort fetched (custom)
SecurityConfigurer
- Pass the obtained (custom)
SecurityConfigurer
configurator into the current WebSecuirty, apply uses the configurator, needless to say
Configure the finalFilterChainProxy
After configuration WebSecurity
, basic SecurityFilterChain
, will configure the finalSecurityFilterChain
WebSecurityConfiguration.java
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
if (!hasConfigurers && !hasFilterChain) {
WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}//1
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break;
}
}
}//2
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}//3
return this.webSecurity.build();//4
}
FilterChain
Create if not presentFilterChain
, either custom or default, usually withFilterChain
WebSecurity
set upFilterSecurityInterceptor
Configure custom
WebSecurity
, the custom class needs to implementWebSecurityCustomizer
the interfaceWebSecurityConfiguration.java
@Autowired(required = false) void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) { this.webSecurityCustomizers = webSecurityCustomizers; }
Return to the final reconfigured
WebSecuriity
(SecurityFilterChain
final version)
buid()
I won’t talk much about the method. IAuthenticationConfiguration
also mentioned it when configuring [HttpSecurity] (# Configure HttpSecurity) before. Here we mainly analyze the differentAbstractConfiguredSecurityBuilder
inheritanceperformBuild()
methodsWebSecurity.java
@Override protected Filter performBuild() throws Exception { int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size(); List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize); List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>(); for (RequestMatcher ignoredRequest : this.ignoredRequests) { SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest); securityFilterChains.add(securityFilterChain); requestMatcherPrivilegeEvaluatorsEntries .add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain)); } for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) { SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build(); securityFilterChains.add(securityFilterChain); requestMatcherPrivilegeEvaluatorsEntries .add(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; this.postBuildAction.run(); return result; }
Analysis shows that the function of this method is to add the default SecurityFilterChain filter and WebSecurity filter to the newly created FilterChainProxy and return
end
At this point, Spring Security roughly defaults to the start-up process source code analysis is over