09 - spring security加载流程
spring security加载流程
文档
- 00 - spring security框架使用
- 01 - spring security自定义登录页面
- 02 - spring security基于配置文件及内存的账号密码
- 03 - spring security自定义登出页面
- 04 - spring security关闭csrf攻击防御
- 05 - spring security权限控制
- 06 - spring security角色和权限设置
- 07 - spring security基于数据库的账号密码
- 08 - spring security基于jdbc的账号密码
说明
- spring security版本:3.2.0
spring security加载流程
-
创建
HttpSecurity
对象,此处用的是@Scope("prototype")
注解,在自定义配置中,操作的就是该对象// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) //package org.springframework.security.config.annotation.web.configuration;@Configuration(proxyBeanMethods = false ) class HttpSecurityConfiguration {// ...@Bean({"org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity"})@Scope("prototype")HttpSecurity httpSecurity() throws Exception {LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(this.objectPostProcessor, passwordEncoder);authenticationBuilder.parentAuthenticationManager(this.authenticationManager());authenticationBuilder.authenticationEventPublisher(this.getAuthenticationEventPublisher());HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, this.createSharedObjects());WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter();webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);http.csrf(Customizer.withDefaults()).addFilter(webAsyncManagerIntegrationFilter).exceptionHandling(Customizer.withDefaults()).headers(Customizer.withDefaults()).sessionManagement(Customizer.withDefaults()).securityContext(Customizer.withDefaults()).requestCache(Customizer.withDefaults()).anonymous(Customizer.withDefaults()).servletApi(Customizer.withDefaults()).apply(new DefaultLoginPageConfigurer());http.logout(Customizer.withDefaults());this.applyCorsIfAvailable(http);this.applyDefaultConfigurers(http);return http;}}
-
默认的
SecurityFilterChain
对象@Configuration(proxyBeanMethods = false ) @ConditionalOnWebApplication(type = Type.SERVLET ) class SpringBootWebSecurityConfiguration {// ...@Configuration(proxyBeanMethods = false)@ConditionalOnDefaultWebSecuritystatic class SecurityFilterChainConfiguration {SecurityFilterChainConfiguration() {}@Bean@Order(2147483642)SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests((requests) -> {((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)requests.anyRequest()).authenticated();});http.formLogin(Customizer.withDefaults());http.httpBasic(Customizer.withDefaults());return (SecurityFilterChain)http.build();}} }
-
上面是默认的
SecurityFilterChain
类型的Bean,实际使用中,我们会自定义SecurityFilterChain
类型的Bean,当我们自定义时,上面的默认配置会失效 -
定义
SecurityFilterChain
类型的Bean时,会注入HttpSecurity
对象,就是在最开始的流程中创建的,在调用HttpSecurity
以下方法时,会创建更多其它相关的对象http.formLogin(Customizer.withDefaults());
,1️⃣http.build()
,6️⃣
-
接口:
SecurityBuilder
-
实现类:
AbstractSecurityBuilder
-
方法:
public final O build() throws Exception
,7️⃣public final O build() throws Exception {if (this.building.compareAndSet(false, true)) {this.object = this.doBuild();return this.object;} else {throw new AlreadyBuiltException("This object has already been built");} }
-
子类:
AbstractConfiguredSecurityBuilder
-
属性:
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers;
-
方法:
protected final O doBuild() throws Exception
,8️⃣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;} }
说明:
- 关注
this.beforeConfigure();
及this.configure();
方法
- 关注
-
方法:
private void configure()
,🔟private void configure() throws Exception {Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();Iterator var2 = configurers.iterator();while(var2.hasNext()) {SecurityConfigurer<O, B> configurer = (SecurityConfigurer)var2.next();configurer.configure(this);}}
说明:这里我们关注
FormLoginConfigurer
-
子类:
HttpSecurity
-
方法:
public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception
,2️⃣public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception {formLoginCustomizer.customize((FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer()));return this; }
说明:
- 实际使用中,我们会在自定义
SecurityFilterChain
类型的Bean时,注入HttpSecurity
对象,并且调用formLogin
方法 formLogin
方法的入参formLoginCustomizer
,一般会以匿名内部类的方式传入,该匿名内部类重写customize
方法customize
方法的入参为FormLoginConfigurer
对象,所以在我们自定义的配置中,实际操作的是FormLoginConfigurer
对象,该对象来自于(FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer())
(FormLoginConfigurer)this.getOrApply(new FormLoginConfigurer())
会向configurers
属性中添加一个键值对this.configurers.put(clazz, configs);
,configs
是List
类型,new FormLoginConfigurer()
是其中的元素
- 实际使用中,我们会在自定义
-
方法:
protected void beforeConfigure() throws Exception
,9️⃣protected void beforeConfigure() throws Exception {if (this.authenticationManager != null) {this.setSharedObject(AuthenticationManager.class, this.authenticationManager);} else {ObservationRegistry registry = this.getObservationRegistry();AuthenticationManager manager = (AuthenticationManager)this.getAuthenticationRegistry().build();if (!registry.isNoop() && manager != null) {this.setSharedObject(AuthenticationManager.class, new ObservationAuthenticationManager(registry, manager));} else {this.setSharedObject(AuthenticationManager.class, manager);}}}
说明:此处会向
sharedObjects
属性中添加一个键值对this.setSharedObject(AuthenticationManager.class, manager);
,该manager
为ProviderManager
对象
-
-
-
-
-
接口:
SecurityConfigurer
-
实现类:
SecurityConfigurerAdapter
-
子类:
AbstractHttpConfigurer
-
子类:
AbstractAuthenticationFilterConfigurer
-
属性:
private F authFilter;
说明:
authFilter
属性的值是UsernamePasswordAuthenticationFilter
对象 -
构造方法,4️⃣
protected AbstractAuthenticationFilterConfigurer(F authenticationFilter, String defaultLoginProcessingUrl) {this();this.authFilter = authenticationFilter;if (defaultLoginProcessingUrl != null) {this.loginProcessingUrl(defaultLoginProcessingUrl);}}
说明:
- 这里的
authenticationFilter
是UsernamePasswordAuthenticationFilter
对象 - 该
UsernamePasswordAuthenticationFilter
对象会加入到FormLoginConfigurer
对象的authFilter
属性中
- 这里的
-
方法:
public void configure(B http)
,1️⃣1️⃣public void configure(B http) throws Exception {PortMapper portMapper = (PortMapper)http.getSharedObject(PortMapper.class);if (portMapper != null) {this.authenticationEntryPoint.setPortMapper(portMapper);}RequestCache requestCache = (RequestCache)http.getSharedObject(RequestCache.class);if (requestCache != null) {this.defaultSuccessHandler.setRequestCache(requestCache);}this.authFilter.setAuthenticationManager((AuthenticationManager)http.getSharedObject(AuthenticationManager.class));this.authFilter.setAuthenticationSuccessHandler(this.successHandler);this.authFilter.setAuthenticationFailureHandler(this.failureHandler);if (this.authenticationDetailsSource != null) {this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);}SessionAuthenticationStrategy sessionAuthenticationStrategy = (SessionAuthenticationStrategy)http.getSharedObject(SessionAuthenticationStrategy.class);if (sessionAuthenticationStrategy != null) {this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);}RememberMeServices rememberMeServices = (RememberMeServices)http.getSharedObject(RememberMeServices.class);if (rememberMeServices != null) {this.authFilter.setRememberMeServices(rememberMeServices);}SecurityContextConfigurer securityContextConfigurer = (SecurityContextConfigurer)http.getConfigurer(SecurityContextConfigurer.class);if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {SecurityContextRepository securityContextRepository = securityContextConfigurer.getSecurityContextRepository();this.authFilter.setSecurityContextRepository(securityContextRepository);}this.authFilter.setSecurityContextHolderStrategy(this.getSecurityContextHolderStrategy());F filter = (AbstractAuthenticationProcessingFilter)this.postProcess(this.authFilter);http.addFilter(filter); }
说明:
this.authFilter.setAuthenticationManager((AuthenticationManager)http.getSharedObject(AuthenticationManager.class));
方法中,(AuthenticationManager)http.getSharedObject(AuthenticationManager.class)
获取到的是ProviderManager
对象,该对象是在HttpSecurity
类的beforeConfigure()
方法中设置的 -
子类:
FormLoginConfigurer
-
构造方法,3️⃣
public FormLoginConfigurer() {super(new UsernamePasswordAuthenticationFilter(), (String)null);this.usernameParameter("username");this.passwordParameter("password"); }
说明:该
FormLoginConfigurer
对象会加入到HttpSecurity
对象的configurers
属性中
-
-
-
-
-
-
抽象类:
AbstractAuthenticationProcessingFilter
-
属性:
private AuthenticationManager authenticationManager;
-
方法:
public void setAuthenticationManager(AuthenticationManager authenticationManager)
,1️⃣2️⃣public void setAuthenticationManager(AuthenticationManager authenticationManager) {this.authenticationManager = authenticationManager; }
说明:该
authenticationManager
为ProviderManager
对象,会加入到UsernamePasswordAuthenticationFilter
对象的authenticationManager
属性中 -
子类:
UsernamePasswordAuthenticationFilter
-
构造方法,5️⃣
public UsernamePasswordAuthenticationFilter() {super(DEFAULT_ANT_PATH_REQUEST_MATCHER); }
说明:该
UsernamePasswordAuthenticationFilter
对象会加入到FormLoginConfigurer
对象的authFilter
属性中
-
-
总结
// 伪代码
ProviderManager manager = new ProviderManager();UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
usernamePasswordAuthenticationFilter.authenticationManager = manager;FormLoginConfigurer formLoginConfigurer = new FormLoginConfigurer();
formLoginConfigurer.authFilter = usernamePasswordAuthenticationFilter;HttpSecurity httpSecurity = new HttpSecurity();
httpSecurity.configurers.put(FormLoginConfigurer.class, Arrays.asList(formLoginConfigurer));
httpSecurity.sharedObject.put(AuthenticationManager.class, manager);
如有不对,欢迎指正!