Análisis de código fuente del proceso de inicio aproximado predeterminado de Spring Security
Comprender el proceso básico.
entender primerospring.factories
fábricas.de.primavera
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 es la clase de configuración principal, principalmente explicamos esta clase
- UserDetailsServiceAutoConfiguration se usa para establecer la contraseña predeterminada, que se configurará cuando SecurityAutoConfiguration configure HttpSecurity, por lo que no entraremos en detalles
- SecurityFilterAutoConfiguration no habla
- Los dos últimos son seguridad OAuth, sin mencionar
Principalmente analizamos SecurityAutoConfiguration
que es una clase de configuración automática, afectada por ella EnableWebSecurit
, será importada HttpSecurityConfiguration
y cargada antes de cargarWebSecurityConfiguration
Su orden de acción es: HttpSecurityConfiguration
configuración HttpSecurityConfiguration
, WebSecurityConfiguration
configuraciónWebSecurity
El proceso también se trata principalmente de: configuración HttpSecurity
--> configurar el básico predeterminado SecurityFilterChain
--> configurar WebSecurity
--> configurar el finalSecurityFilterChain
También puede entenderse como: ¿cómo crear el definitivo SecurityFilterChain
?
Anotaciones EnableWebSecurity y EnableGlobalAuthentication
@Import({
WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
}
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}
configuraciónHttpSecurity
Desde HttpSecurityConfiguration
el principio, esta clase es la clase de configuración básica de HttpSecurity, la configuración es la siguiente:
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;
}
Inyección de dependencia de una configuración de autenticación, precargando la configuración de autenticación que debe configurarse automáticamente antes,
Esta clase crea tres objetos Bean importantes: AuthenticationManagerBuild, InitializeUserDetailsBeanManagerConfigurer e InitializeAuthenticationProviderBeanManagerConfigurer
utilizado respectivamente
- Cree el administrador de autenticación
- Se utiliza para inicializar UserDetailsServiceAutoConfiguration en spring.factories, su función es proporcionar un nombre de usuario y una contraseña predeterminados,
- Inicializar el administrador de autenticación de usuarios (ProviderManager)
Crear un cargador de contraseña perezoso
Crear un generador de administrador de autenticación
Cree un administrador de autenticación
Configuración de autenticación.java
public AuthenticationManager getAuthenticationManager() throws Exception { //... for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) { authBuilder.apply(config); }//1 this.authenticationManager = authBuilder.build();//2 //... return this.authenticationManager; }
El constructor usa la configuración de autenticación global, que se mencionó anteriormente al crear AuthenticationConfiguration
Cree el administrador de autenticación
Mire directamente el último 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; } }
Operación antes de la inicialización
Inicializar el configurador
Operación antes de la configuración
Configura el configurador, hay muchos configuradores, así que no voy a hablar de eso, el proceso de configuración es el siguiente:
AbstractConfiguredSecurityBuilder
private void configure() throws Exception { Collection<SecurityConfigurer<O, B>> configurers = getConfigurers(); for (SecurityConfigurer<O, B> configurer : configurers) { configurer.configure((B) this); } }
empezar a construir
Este método crea y devuelve un PrivideManager
AuthenticationManagerBuilder.java
protected ProviderManager performBuild() throws Exception { ProviderManager providerManager = new ProviderManager(this.authenticationProviders, this.parentAuthenticationManager); return providerManager; }
Crear , inyectar lo
HttpSecurity
anteriorPrivider
HttpSecurity
HttpSecurity
Configurar el configurador básico
configuraciónSecurityFilterChain
Una vez completada la configuración predeterminada HttpSecurity
, comenzará a configurar el valor predeterminado SecurityFilterChain
,
Veamos las clases SecurityAutoConfiguration
importadas.SpringBootWebSecurityConfiguration
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
}
}
Esta clase solo se configurará cuando se cumpla la WebSecurity predeterminada, de la siguiente manera:
@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 }
- cumplir con
DefaultWebSecurityCondition
las condiciones- Satisfecho con
SecurityFilterChain.class
susHttpSecurity.class
dos clases- Conoce la falta
WebSecurityConfigurerAdapter.class
deSecurityFilterChain.class
dos beans, y la configuración de seguridad predeterminada no tiene estas dos clasesCree la SecurityFilterChain básica predeterminada, donde SecurityFilterChain tiene quince filtros básicos:
configuraciónWebSecurity
Después de configurar el SecurityFilterChain básico predeterminado, se configuraráWebSecurity
vemos WebSecurityConfiguration
clase
Primero mira cómo está configurado WebSecurity
, de la siguiente manera:
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;
}
- Primero observe los parámetros formales con anotaciones
@Value
, esta anotación obtiene todos los configurados previamenteWebSeucurityConfigurer
(es decir, personalizadosWebSecurityConfigurer
), y pasará todos los configuradores a los creados actualmente a continuaciónWebSecurity
.- crear
WebSecurity
- Ordenar obtenido (personalizado)
SecurityConfigurer
- Pase el
SecurityConfigurer
configurador obtenido (personalizado) al WebSecuirty actual, aplique los usos del configurador, no hace falta decir
Configurar la finalFilterChainProxy
Después de la configuración WebSecurity
, básica SecurityFilterChain
, configurará la 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
Crear si no está presenteFilterChain
, ya sea personalizado o predeterminado, generalmente conFilterChain
WebSecurity
configuraciónFilterSecurityInterceptor
Configurar personalizado
WebSecurity
, la clase personalizada necesita implementarWebSecurityCustomizer
la interfazWebSecurityConfiguration.java
@Autowired(required = false) void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) { this.webSecurityCustomizers = webSecurityCustomizers; }
Volver a la final reconfigurada
WebSecuriity
(SecurityFilterChain
versión final)
buid()
No hablaré mucho sobre el método,AuthenticationConfiguration
también lo mencioné al configurar [HttpSecurity] (# Configure HttpSecurity) antes, aquí analizamos principalmente los diferentes métodosAbstractConfiguredSecurityBuilder
de herenciaperformBuild()
WebSecurity.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; }
El análisis muestra que la función de este método es agregar el filtro SecurityFilterChain predeterminado y el filtro WebSecurity al FilterChainProxy recién creado y devolver
fin
En este punto, Spring Security se basa aproximadamente en el proceso de inicio. El análisis del código fuente ha terminado.