概述 SecurityAutoConfiguration主要负责在项目启动时为当前的web容器添加一些必要的配置类
SecurityAutoConfiguration 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Configuration @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); } }
将DefaultAuthenticationEventPublisher注册到spring容器中
将SecurityProperties注册到spring容器中
将SpringBootWebSecurityConfiguration、WebSecurityEnablerConfiguration和SecurityDataConfiguration注册到当前容器中
这里我们主要关注一下SpringBootWebSecurityConfiguration、WebSecurityEnablerConfiguration这两个配置类
SpringBootWebSecurityConfiguration 1 2 3 4 5 6 7 8 9 10 11 12 13 @Configuration @ConditionalOnClass(WebSecurityConfigurerAdapter.class) @ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) @ConditionalOnWebApplication(type = Type.SERVLET) public class SpringBootWebSecurityConfiguration { @Configuration @Order(SecurityProperties.BASIC_AUTH_ORDER) static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter { } }
判断类路径下是否有WebSecurityConfigurerAdapter,正常情况是肯定有的,满足条件
判断spring容器中是否有WebSecurityConfigurerAdapter实例,由于我们没有自己编写自己的类继承它,所以容器中是没有改实例的,满足条件
判断当前web应用是不是基于servlet的,springmvc就是基于servlet的,满足条件
综上,满足所有条件,将SpringBootWebSecurityConfiguration和DefaultConfigurerAdapter注册到spring容器中
WebSecurityEnablerConfiguration 1 2 3 4 5 6 7 8 @Configuration @ConditionalOnBean(WebSecurityConfigurerAdapter.class) @ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @EnableWebSecurity public class WebSecurityEnablerConfiguration {}
判断spring容器中是否有WebSecurityConfigurerAdapter实例,在上一步的SpringBootWebSecurityConfiguration配置中,最终将WebSecurityConfigurerAdapter的实例DefaultConfigurerAdapter注册到了spring容器中,满足条件
判断spring容器中是否没有bean的名称为springSecurityFilterChain ,默认我们没有自定义这个bean,满足条件
判断当前web应用是不是基于servlet的,springmvc就是基于servlet的,满足条件
综上,满足所有条件,将WebSecurityEnablerConfiguration实例注册到spring容器中,并且开启EnableWebSecurity注解,这个EnableWebSecurity注解很重要,下面我们来着重分析一下它
EnableWebSecurity 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @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 ; }
将WebSecurityConfiguration、SpringWebMvcImportSelector和OAuth2ImportSelector注册到spring容器中
开启EnableGlobalAuthentication注解
接下来我们分析一下WebSecurityConfiguration这个配置类为我们配置了哪些类
WebSecurityConfiguration 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 @Configuration public class WebSecurityConfiguration implements ImportAware , BeanClassLoaderAware { private WebSecurity webSecurity; private Boolean debugEnabled; private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers; private ClassLoader beanClassLoader; @Autowired(required = false) private ObjectPostProcessor<Object> objectObjectPostProcessor; @Bean public static DelegatingApplicationListener delegatingApplicationListener () { return new DelegatingApplicationListener (); } @Bean @DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler () { return webSecurity.getExpressionHandler(); } @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(); } @Bean @DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public WebInvocationPrivilegeEvaluator privilegeEvaluator () throws Exception { return webSecurity.getPrivilegeEvaluator(); } @Autowired(required = false) public void setFilterChainProxySecurityConfigurer ( ObjectPostProcessor<Object> objectPostProcessor, // 注入autowiredWebSecurityConfigurersIgnoreParents这个bean的getWebSecurityConfigurers返回的值 @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception { webSecurity = objectPostProcessor .postProcess(new WebSecurity (objectPostProcessor)); if (debugEnabled != null ) { webSecurity.debug(debugEnabled); } Collections.sort(webSecurityConfigurers, 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; } for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) { webSecurity.apply(webSecurityConfigurer); } this .webSecurityConfigurers = webSecurityConfigurers; } @Bean public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents ( ConfigurableListableBeanFactory beanFactory) { return new AutowiredWebSecurityConfigurersIgnoreParents (beanFactory); } private static class AnnotationAwareOrderComparator extends OrderComparator { private static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator (); @Override protected int getOrder (Object obj) { return lookupOrder(obj); } private static int lookupOrder (Object obj) { if (obj instanceof Ordered) { return ((Ordered) obj).getOrder(); } if (obj != null ) { Class<?> clazz = (obj instanceof Class ? (Class<?>) obj : obj.getClass()); Order order = AnnotationUtils.findAnnotation(clazz, Order.class); if (order != null ) { return order.value(); } } return Ordered.LOWEST_PRECEDENCE; } } public void setImportMetadata (AnnotationMetadata importMetadata) { Map<String, Object> enableWebSecurityAttrMap = importMetadata .getAnnotationAttributes(EnableWebSecurity.class.getName()); AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes .fromMap(enableWebSecurityAttrMap); debugEnabled = enableWebSecurityAttrs.getBoolean("debug" ); if (webSecurity != null ) { webSecurity.debug(debugEnabled); } } public void setBeanClassLoader (ClassLoader classLoader) { this .beanClassLoader = classLoader; } }
从ConfigurableListableBeanFactory中找到所有SecurityConfigurer<Filter, WebSecurity>,然后初始化webSecurity,在对所有SecurityConfigurer进行排序
在springSecurityFilterChain实例注册到spring容器中后,将WebInvocationPrivilegeEvaluator、SecurityExpressionHandler、DelegatingApplicationListener等实例注册到spring容器中
EnableGlobalAuthentication 1 2 3 4 5 6 7 8 @Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value = { java.lang.annotation.ElementType.TYPE }) @Documented @Import(AuthenticationConfiguration.class) @Configuration public @interface EnableGlobalAuthentication {}
@EnableWebSecurity
被EnableGlobalAuthentication
注解了,从EnableGlobalAuthentication注解我们可以看到它的作用是将AuthenticationConfiguration注册到spring容器中
AuthenticationConfiguration 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 @Configuration @Import(ObjectPostProcessorConfiguration.class) public class AuthenticationConfiguration { private AtomicBoolean buildingAuthenticationManager = new AtomicBoolean (); private ApplicationContext applicationContext; private AuthenticationManager authenticationManager; private boolean authenticationManagerInitialized; private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections .emptyList(); private ObjectPostProcessor<Object> objectPostProcessor; @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 = authenticationManagerBuilder( this .objectPostProcessor, this .applicationContext); 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) throws Exception { Collections.sort(configurers, AnnotationAwareOrderComparator.INSTANCE); this .globalAuthConfigurers = configurers; } @Autowired public void setApplicationContext (ApplicationContext applicationContext) { this .applicationContext = applicationContext; } @Autowired public void setObjectPostProcessor (ObjectPostProcessor<Object> objectPostProcessor) { this .objectPostProcessor = objectPostProcessor; } @SuppressWarnings("unchecked") private <T> T lazyBean (Class<T> interfaceName) { LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource (); String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( applicationContext, interfaceName); if (beanNamesForType.length == 0 ) { return null ; } Assert.isTrue(beanNamesForType.length == 1 , () -> "Expecting to only find a single bean for type " + interfaceName + ", but found " + Arrays.asList(beanNamesForType)); lazyTargetSource.setTargetBeanName(beanNamesForType[0 ]); lazyTargetSource.setBeanFactory(applicationContext); ProxyFactoryBean proxyFactory = new ProxyFactoryBean (); proxyFactory = objectPostProcessor.postProcess(proxyFactory); proxyFactory.setTargetSource(lazyTargetSource); return (T) proxyFactory.getObject(); } private AuthenticationManager getAuthenticationManagerBean () { return lazyBean(AuthenticationManager.class); } private static <T> T getBeanOrNull (ApplicationContext applicationContext, Class<T> type) { try { return applicationContext.getBean(type); } catch (NoSuchBeanDefinitionException notFound) { return null ; } } private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter { private final ApplicationContext context; private static final Log logger = LogFactory .getLog(EnableGlobalAuthenticationAutowiredConfigurer.class); public EnableGlobalAuthenticationAutowiredConfigurer (ApplicationContext context) { this .context = context; } @Override public void init (AuthenticationManagerBuilder auth) { Map<String, Object> beansWithAnnotation = context .getBeansWithAnnotation(EnableGlobalAuthentication.class); if (logger.isDebugEnabled()) { logger.debug("Eagerly initializing " + beansWithAnnotation); } } } static final class AuthenticationManagerDelegator implements AuthenticationManager { private AuthenticationManagerBuilder delegateBuilder; private AuthenticationManager delegate; private final Object delegateMonitor = new Object (); AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) { Assert.notNull(delegateBuilder, "delegateBuilder cannot be null" ); this .delegateBuilder = delegateBuilder; } @Override public Authentication authenticate (Authentication authentication) throws AuthenticationException { if (this .delegate != null ) { return this .delegate.authenticate(authentication); } synchronized (this .delegateMonitor) { if (this .delegate == null ) { this .delegate = this .delegateBuilder.getObject(); this .delegateBuilder = null ; } } return this .delegate.authenticate(authentication); } @Override public String toString () { return "AuthenticationManagerDelegator [delegate=" + this .delegate + "]" ; } } static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder { private PasswordEncoder defaultPasswordEncoder; DefaultPasswordEncoderAuthenticationManagerBuilder( ObjectPostProcessor<Object> objectPostProcessor, PasswordEncoder defaultPasswordEncoder) { super (objectPostProcessor); this .defaultPasswordEncoder = defaultPasswordEncoder; } @Override public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication () throws Exception { return super .inMemoryAuthentication() .passwordEncoder(this .defaultPasswordEncoder); } @Override public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication () throws Exception { return super .jdbcAuthentication() .passwordEncoder(this .defaultPasswordEncoder); } @Override public <T extends UserDetailsService > DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService ( T userDetailsService) throws Exception { return super .userDetailsService(userDetailsService) .passwordEncoder(this .defaultPasswordEncoder); } } static class LazyPasswordEncoder implements PasswordEncoder { private ApplicationContext applicationContext; private PasswordEncoder passwordEncoder; LazyPasswordEncoder(ApplicationContext applicationContext) { this .applicationContext = applicationContext; } @Override public String encode (CharSequence rawPassword) { return getPasswordEncoder().encode(rawPassword); } @Override public boolean matches (CharSequence rawPassword, String encodedPassword) { return getPasswordEncoder().matches(rawPassword, encodedPassword); } @Override public boolean upgradeEncoding (String encodedPassword) { return getPasswordEncoder().upgradeEncoding(encodedPassword); } private PasswordEncoder getPasswordEncoder () { if (this .passwordEncoder != null ) { return this .passwordEncoder; } PasswordEncoder passwordEncoder = getBeanOrNull(this .applicationContext, PasswordEncoder.class); if (passwordEncoder == null ) { passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); } this .passwordEncoder = passwordEncoder; return passwordEncoder; } @Override public String toString () { return getPasswordEncoder().toString(); } } }
配置了AuthenticationManagerBuilder、InitializeUserDetailsBeanManagerConfigurer、InitializeAuthenticationProviderBeanManagerConfigurer这些必要的配置类,同时也通过@Import(ObjectPostProcessorConfiguration.class)
将ObjectPostProcessor注入到spring容器中了
ObjectPostProcessorConfiguration 1 2 3 4 5 6 7 8 9 10 @Configuration public class ObjectPostProcessorConfiguration { @Bean public ObjectPostProcessor<Object> objectPostProcessor ( AutowireCapableBeanFactory beanFactory) { return new AutowireBeanFactoryObjectPostProcessor (beanFactory); } }
默认的ObjectPostProcessor就是AutowireBeanFactoryObjectPostProcessor
总结
将DefaultAuthenticationEventPublisher注册到spring容器中
将DefaultConfigurerAdapter注册到spring容器中
开启@EnableWebSecurity注解,将springSecurityFilterChain,WebSecurity,ObjectPostProcessor,AuthenticationManagerBuilder等配置类注入到spring容器中