
ethanzhl
2023/01/08阅读:64主题:全栈蓝
Spring Security 启动原理
自动配置
Spring Boot启动时会自动加载 spring.factories 文件中 key 为 EnableAutoConfiguration
的配置,其中关于 Spring Security 的配置如下
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
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.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
......
SecurityAutoConfiguration
@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);
}
}
这里主要干了三件事
-
加载了 SecurityProperties
配置文件 -
导入了三个配置类 -
创建一个默认的认证事件发布器 DefaultAuthenticationEventPublisher
SpringBootWebSecurityConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
public class SpringBootWebSecurityConfiguration {
@Configuration(proxyBeanMethods = false)
@Order(SecurityProperties.BASIC_AUTH_ORDER)
static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
}
}
在开发者没有提供 WebSecurityConfigurerAdapter
实例的情况下,提供一个默认的实例 DefaultConfigurerAdapter
SecurityDataConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SecurityEvaluationContextExtension.class)
public class SecurityDataConfiguration {
@Bean
@ConditionalOnMissingBean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
在开发者没有提供SecurityEvaluationContextExtension
实例的情况下,提供一个实例 SecurityEvaluationContextExtension
WebSecurityEnablerConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {
}
配置类引入了一个注解@EnableWebSecurity
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
-
@EnableWebSecurity
是一个组合注解,导入了三个配置类-
WebSecurityConfiguration
用来配置WebScrurity
-
SpringWebMvcImportSelector
判断当前环境是否存在Spring MVC,如果存在,则引入相关配置 -
OAuth2ImportSelector
判断当前环境是否存在OAuth2,如果存在,则引入相关配置
-
-
@EnableGlobalAuthentication
导入了配置类AuthenticationConfiguration
Spring Security 的自动化配置主要倒入了两个配置类 WebSecurityConfiguration
和AuthenticationConfiguration
WebSecurityConfiguration
❝❞
WebSecurityConfiguration
的主要功能就是为了构建 Spring Security 过滤器链代理对象FilterChainProxy
,FilterChainProxy
是由WebSecurity
来构建的,所以在WebSecurityConfiguration
中首先会构建WebSecurity
对象,再由WebSecurity
对象构建FilterChainProxy
。
AutowiredWebSecurityConfigurersIgnoreParents
final class AutowiredWebSecurityConfigurersIgnoreParents {
private final ConfigurableListableBeanFactory beanFactory;
AutowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "beanFactory cannot be null");
this.beanFactory = beanFactory;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<SecurityConfigurer<Filter, WebSecurity>> `getWebSecurityConfigurers`() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory.getBeansOfType(WebSecurityConfigurer.class);
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
}
在getWebSecurityConfigurers()
方法中主要通过调用beanFactory.getBeansOfType(WebSecurityConfigurer.class)
方法来获取Spring容器中所有的WebSecurityConfigurer
实例,也就是开发者自定义的各种继承至WebSecurityConfigurerAdapter
的配置类,如果开发者没有定义任何自定义的配置类,这里获取到的就是前面SpringBootWebSecurityConfiguration类中提供的默认配置类DefaultConfigurerAdapter
-
「setFilterChainProxySecurityConfigurer()」
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
// 1、创建创建了一个 WebSecurity,经过后置处理器处理之后加入到spring容器中
webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (debugEnabled != null) {
webSecurity.debug(debugEnabled);
}
// 2、对配置类进行排序
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
Integer order = 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;
previousConfig = config;
}
// 3、遍历配置类,将其加入到`WebSecurity`父类的configurers集合中(将来遍历该集合并分别调用配置类的`init`和`configure`方法完成配置类的初始化和配置操作)
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
webSecurity.apply(webSecurityConfigurer);
}
// 4、缓存配置类列表
this.webSecurityConfigurers = webSecurityConfigurers;
}
该方法主要用来初始化WebSecurity对象,同时收集到所有的自定义配置类
-
「springSecurityFilterChain」()
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
这里首先判断webSecurityConfigurers
集合中是否存在配置类,如果不存在,则创建一个匿名的WebSecurityConfigurerAdapter
并注册到 Spring 容器中,否则,直接调用 WebSecurity
的build
方法进行构建。
-
「WebSecurity#build()」
classDiagram
AbstractSecurityBuilder~O~ <|-- AbstractConfiguredSecurityBuilder~O,B~
AbstractConfiguredSecurityBuilder <|-- WebScurity
SecurityConfigurer~O,B extends SecurityBuilder~ <|-- WebSecurityConfigurer~WebScurity~
WebSecurityConfigurer~WebScurity~ <|.. WebSecurityConfigurerAdapter
class AbstractSecurityBuilder {
+O build()
#O doBuild()
}
class AbstractConfiguredSecurityBuilder {
#O doBuild()
-void init()
-void configure()
#O performBuild()
}
class WebScurity {
#Filter performBuild()
}
class SecurityConfigurer {
+void init()
+void configure()
}
class WebSecurityConfigurer {
+void init()
+void configure()
}
class WebSecurityConfigurerAdapter {
+void configure(WebSecurity web)
}
WebScurity
的build
方法最终会调用父类AbstractConfiguredSecurityBuilder
的doBuild
方法
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
beforeInit();
init();
buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();
buildState = BuildState.BUILDING;
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
doBuild
方法中调用init
、configure
、performBuild
方法
private void **`init`**() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
private void **`configure`**() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
protected abstract O performBuild() throws Exception;
WebSecurityConfigurerAdapter
中实现了 init
、configure
方法
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
});
}
// 子类可以重写该方法实现自定义逻辑
public void configure(WebSecurity web) throws Exception {
}
// 子类可以重写该方法实现自定义逻辑
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableLocalConfigureAuthenticationBldr = true;
}
// 子类可以重写该方法实现自定义逻辑
protected void configure(HttpSecurity http) throws Exception {
logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
AuthenticationManagerBuilder
、HttpSecurity
、WebSecurity
分别都重写 performBuild
方法
public class AuthenticationManagerBuilder {
......
@Override
protected ProviderManager performBuild() throws Exception {
if (!isConfigured()) {
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
if (eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
}
if (eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(eventPublisher);
}
providerManager = postProcess(providerManager);
return providerManager;
}
}
public final class HttpSecurity {
......
@Override
protected DefaultSecurityFilterChain performBuild() {
filters.sort(comparator);
return new DefaultSecurityFilterChain(requestMatcher, filters);
}
}
public final class WebSecurity {
......
@Override
protected Filter performBuild() throws Exception {
Assert.state(
!securityFilterChainBuilders.isEmpty(),
() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ "More advanced users can invoke "
+ WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
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;
if (debugEnabled) {
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);
}
postBuildAction.run();
return result;
}
}
AuthenticationConfiguration
❝在Spring Security 自动化配置类中导入的另一配置类是
❞AuthenticationConfiguration
,该类的功能主要是做全局配置,同时提供一个全局的AuthticationManager实例。
@Configuration(proxyBeanMethods = false)
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
......
}
导入了一个配置类ObjectPostProcessorConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ObjectPostProcessorConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ObjectPostProcessor<Object> objectPostProcessor(
AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
ObjectPostProcessorConfiguration
配置类主要提供了一个后置对象处理器ObjectPostProcessor
实例, 具体实现类是AutowireBeanFactoryObjectPostProcessor
,该实例主要用来将一个对象注册到Spring容器中去,其他配置类中所见到的ObjectPostProcessor
实例就是这里提供的。
@Configuration(proxyBeanMethods = false)
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
......
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context, AuthenticationEventPublisher.class);
DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);
if (authenticationEventPublisher != null) {
result.authenticationEventPublisher(authenticationEventPublisher);
}
return result;
}
@Bean
public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(
ApplicationContext context) {
return new EnableGlobalAuthenticationAutowiredConfigurer(context);
}
@Bean
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
return new InitializeUserDetailsBeanManagerConfigurer(context);
}
@Bean
public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {
return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
}
public AuthenticationManager getAuthenticationManager() throws Exception {
if (this.authenticationManagerInitialized) {
return this.authenticationManager;
}
AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
if (this.buildingAuthenticationManager.getAndSet(true)) {
return new AuthenticationManagerDelegator(authBuilder);
}
for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
authBuilder.apply(config);
}
authenticationManager = authBuilder.build();
if (authenticationManager == null) {
authenticationManager = getAuthenticationManagerBean();
}
this.authenticationManagerInitialized = true;
return authenticationManager;
}
@Autowired(required = false)
public void setGlobalAuthenticationConfigurers(
List<GlobalAuthenticationConfigurerAdapter> configurers) {
configurers.sort(AnnotationAwareOrderComparator.INSTANCE);
this.globalAuthConfigurers = configurers;
}
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Autowired
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
}
......
}
-
首先定义了一个 AuthenticationManagerBuilder
实例,目的是为了构建全局的AuthticationManager
对象 -
接下来构建了3个Bean -
InitializeAuthenticationProviderBeanManagerConfigurer
初始化全集的AuthticationProvider
对象 -
InitializeUserDetailsBeanManagerConfigurer
初始化全局的UserDetailsService
对象 -
EnableGlobalAuthenticationAutowiredConfigurer
从Spring容器中加载被@EnableGlobalAuthentication
注解标记的Bean
-
-
getAuthenticationManager()
方法则用来构建具体的AuthenticationManager
对象-
判断AuthenticationManager是否已经初始化,如果已经初始化,则直接返回 AuthenticationManager
对象 -
否则就先从Spring容器中获取 AuthenticationManagerBuilder
对象 -
AuthenticationManagerDelegator
实现AuthenticactionManager
接口,主要是为了防止在初始化AuthenticationManager
时进行无限递归 -
拿到 AuthenticationManagerBuilder
对象后,遍历globalAuthConfigurers
配置类集合(也就是第二点所说的三个配置类),将配置类分别添加到AuthenticationManagerBuilder
对象父类的configurers
集合中
-
-
进行构建,返回结果
🔼 「整体来说AuthticationConfiguration的作用主要体现在两个方面:」
-
导入了 ObjectPostProcessorConfiguration
配置类 -
提供了一个全局的AuthenticationManager对象
如果开发这在自定义的配置类中重写了configure(AuthenticationBuilder builder)
方法,这里的全局AuthenticationManager
将不会生效
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
......
// 如果重写该方法,`disableLocalConfigureAuthenticationBldr`的值将还是默认初始化的false
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.`disableLocalConfigureAuthenticationBldr` = true;
}
protected AuthenticationManager authenticationManager() throws Exception {
if (!authenticationManagerInitialized) {
configure(localConfigureAuthenticationBldr);
if (`disableLocalConfigureAuthenticationBldr`) {
// 这里的`authenticationConfiguration`就是上面说的全局配置类
authenticationManager = `authenticationConfiguration`.getAuthenticationManager();
}
else {
authenticationManager = localConfigureAuthenticationBldr.build();
}
authenticationManagerInitialized = true;
}
return authenticationManager;
}
......
}
SecurityFilterAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class })
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class SecurityFilterAutoConfiguration {
private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {
if (securityProperties.getFilter().getDispatcherTypes() == null) {
return null;
}
return securityProperties.getFilter().getDispatcherTypes().stream()
.map((type) -> DispatcherType.valueOf(type.name()))
.collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class)));
}
}
SecurityFilterAutoConfiguration
配置类提供了一个DelegatingFilterProxyRegistrationBean
实例,此时DelegatingFilterProxyRegistrationBean
对象的属性targetBeanName
的值为 "springSecurityFilterChain"
UserDetailsServiceAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(AuthenticationManager.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnMissingBean(
value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class },
type = { "org.springframework.security.oauth2.jwt.JwtDecoder",
"org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector" })
public class UserDetailsServiceAutoConfiguration {
private static final String NOOP_PASSWORD_PREFIX = "{noop}";
private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile("^\\{.+}.*$");
private static final Log logger = LogFactory.getLog(UserDetailsServiceAutoConfiguration.class);
@Bean
@ConditionalOnMissingBean(type = "org.springframework.security.oauth2.client.registration.ClientRegistrationRepository")
@Lazy
public InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties, ObjectProvider<PasswordEncoder> passwordEncoder) {
SecurityProperties.User user = properties.getUser();
List<String> roles = user.getRoles();
return new InMemoryUserDetailsManager(
User.withUsername(user.getName())
.password(getOrDeducePassword(user, passwordEncoder.getIfAvailable()))
.roles(StringUtils.toStringArray(roles)).build());
}
private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) {
String password = user.getPassword();
if (user.isPasswordGenerated()) {
logger.info(String.format("%n%nUsing generated security password: %s%n", user.getPassword()));
}
if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {
return password;
}
return NOOP_PASSWORD_PREFIX + password;
}
}
主要提供了一个默认的基于内存的InMemoryUserDetailsManager
用户信息管理器,并利用SecurityProperties
中定义的默认用户,创建一个默认的用户账号,可以通过提供AuthenticationManager、AuthenticationProvider、UserDetailsService
的bean来覆盖默认配置。
流程分析
WebSecurityConfiguration
该配置类中setFilterChainProxySecurityConfigurer
方法主要做了如下事情:
-
提供了一个 AutowiredWebSecurityConfigurersIgnoreParents
实例对象 -
在 setFilterChainProxySecurityConfigurer
方法中调用 1 中的AutowiredWebSecurityConfigurersIgnoreParents
实例对象的getWebSecurityConfigurers
方法得到用户自定义的所有继承自WebSecurityConfigurerAdapter
实例对象集合,如果没有自定义对象,这里得到的就是Spring Security提供的默认的DefaultConfigurerAdapter
实例对象 -
创建了一个 WebSecurity
对象,调用AutowireBeanFactoryObjectPostProcessor
实例的postProcess
方法将WebSecurity
对象注册到Spring容器中 -
遍历2中得到的用户自定义 WebSecurityConfigurerAdapter
子类集合,添加到WebSecurity
父类的configurers
集合中 -
在 springSecurityFilterChain
方法中调用WebSecurity
的build
方法,实际调用的是WebSecurity
父类的doBuild
方法,在doBuild
方法中,遍历2中得到的自定义配置类集合,调用init
、configure
方法,执行初始化及配置逻辑 -
WebSecurityConfigurerAdapter
子类在调用init
方法初始化时,先调用getHttp
,执行authenticationManager
方法,根据子类是否重写configure(AuthenticationManagerBuilder auth)
方法,判断是否需要调用AuthenticationConfiguration
的getAuthenticationManager
方法获得一个全局的AuthenticationManager
实例对象,给局部创建的AuthenticationManager
设置父AuthenticationManager
为authenticationManager
方法的返回值,然后创建一个HttpSecurity
对象,并设置AutowireBeanFactoryObjectPostProcessor
后置处理器对象及局部的AuthenticationManager
对象,返回HttpSecurity
对象 -
init
的初始化的下一步是拿到6 返回的HttpSecurity
对象,并添加到WebSecurity
中的securityFilterChainBuilders
集合中 -
configure
方法没做任何操作,留给子类可以重写该方法实现自定义的逻辑 -
最后执行 WebSecurity
对象 的performBuild
方法,该方法会遍历securityFilterChainBuilders
集合,执行SecurityBuilder
的build
方法,此时的SecurityBuilder
实际为7中添加的HttpSecurity
实例对象,而HttpSecurity
类定义中这样写到public final class HttpSecurity implements SecurityBuilder<DefaultSecurityFilterChain>,
由此可见,HttpSecurity
对象的build
实际会创建一个DefaultSecurityFilterChain
默认过滤器链对象,回到WebSecurity
对象 的performBuild
方法,得到DefaultSecurityFilterChain
并添加到securityFilterChains
集合中,接下来创建一个FilterChainProxy
对象,在构造方法中设置其filterChains
集合属性值为上面得到的securityFilterChains
过滤器链集合,返回FilterChainProxy
实例对象 -
至此 WebSecurityConfiguration
中的springSecurityFilterChain
方法才算执行完毕,得到一个包含过滤器链列表的FilterChainProxy
实例对象,并将FilterChainProxy
对象注册到Spring容器中,bean
的name
为springSecurityFilterChain
WebSecurity
WebSecurity
是由WebSecurityConfiguration
创建的,用来创建FilterChainProxy
,也就是SpringSecurityFilterChain
(springSecurityFilterChain
)。springSecurityFilterChain
是DelegatingFilterProxy
委托的Filter
。 对WebSecurity
的自定义可以通过创建WebSecurityConfigurer
或者更可能的是通过覆盖WebSecurityConfigurerAdapter
来实现,WebSecurity
在build中会为每个WebSecurityConfigurerAdapter
子类生成一个过滤器链DefaultSecurityFilterChain
,其中的filter
列表为HttpSecurity
构建过程中,遍历父类configurers
,执行配置类的configure
方法得到的Filter
对象。
WebSecurityConfigurerAdapter
❝为创建
❞WebSecurityConfigurer
实例提供了一个方便的基类。该实现允许通过重写方法进行定制。 将自动应用从SpringFactoriesLoader中查找AbstractHttpConfigurer
的结果,以允许开发人员扩展默认值。为此,您必须创建一个扩展AbstractHttpConfigurer
的类,然后在类路径下中创建“META-INF/spring.factories
”文件
init
-
调用 getHttp
方法-
调用 authenticationManager
方法,创建一个AuthenticationManager
实例对象ProviderManager
-
根据 disableLocalConfigureAuthenticationBldr
判断是否禁止本地配置AuthenticationManagerBuilder
-
执行 AuthenticationManagerBuilder
的build
方法-
执行 performBuild
方法-
创建一个 ProviderManager
对象,保存开发者添加的AuthenticationProvider
,在「对象后置处理器」中处理一遍,将ProviderManager
注册到Spring容器中
-
-
-
-
设置本地创建的 AuthenticationManagerBuilder
对象的父类为上面生成的ProviderManager
实例对象 -
创建共享对象集合 sharedObjects
-
sharedObjects.putAll(localConfigureAuthenticationBldr.getSharedObjects());
sharedObjects.put(UserDetailsService.class, userDetailsService());
sharedObjects.put(ApplicationContext.class, context);
sharedObjects.put(ContentNegotiationStrategy.class, contentNegotiationStrategy);
sharedObjects.put(AuthenticationTrustResolver.class, trustResolver);
// 在HttpSecurity构造方法中进行设置
sharedObjects.put(AuthenticationManagerBuilder.class, authenticationBuilder);
作者介绍
