概述
spring-boot-starter-security和spring其它系列的starter一样,依赖spring-boot-autoconfigure,根据其META-INF下的spring.factories加载自动配置类,然后进行一系列的初始化配置。查看spring.factories下的EnableAutoConfiguration和spring-security相关的一共有以下几种自动配置
1 2 3 4 5 6
| SecurityAutoConfiguration SecurityRequestMatcherProviderAutoConfiguration UserDetailsServiceAutoConfiguration SecurityFilterAutoConfiguration ReactiveSecurityAutoConfiguration ReactiveUserDetailsServiceAutoConfiguration
|
下面对这些自动配置类进行简单的分析
SecurityAutoConfiguration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @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); }
}
|
SecurityRequestMatcherProviderAutoConfiguration
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
| @Configuration
@ConditionalOnClass({ RequestMatcher.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) public class SecurityRequestMatcherProviderAutoConfiguration {
@Configuration @ConditionalOnClass(DispatcherServlet.class) @ConditionalOnBean(HandlerMappingIntrospector.class) public static class MvcRequestMatcherConfiguration {
@Bean @ConditionalOnClass(DispatcherServlet.class) public RequestMatcherProvider requestMatcherProvider( HandlerMappingIntrospector introspector) { return new MvcRequestMatcherProvider(introspector); }
}
@Configuration @ConditionalOnClass(ResourceConfig.class) @ConditionalOnMissingClass("org.springframework.web.servlet.DispatcherServlet") @ConditionalOnBean(JerseyApplicationPath.class) public static class JerseyRequestMatcherConfiguration {
@Bean public RequestMatcherProvider requestMatcherProvider( JerseyApplicationPath applicationPath) { return new JerseyRequestMatcherProvider(applicationPath); }
}
}
|
UserDetailsServiceAutoConfiguration
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
| @Configuration
@ConditionalOnClass(AuthenticationManager.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnMissingBean({ AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class }) 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; }
}
|
SecurityFilterAutoConfiguration
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
| @Configuration
@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 .collectingAndThen(Collectors.toSet(), EnumSet::copyOf)); }
}
|
剩下的ReactiveSecurityAutoConfiguration和ReactiveUserDetailsServiceAutoConfiguration是spring5新增的reactive非阻塞的web框架中的配置类,不在本次的讨论之中,就不做分析了。
总结
本章主要分析了spring-security在项目启动时主要加载了哪些自动配置类,从spring-boot-autoconfigure的META-INF下的spring.factories文件中,我们可以发现,在项目启动时主要是加载SecurityAutoConfiguration
SecurityRequestMatcherProviderAutoConfiguration、UserDetailsServiceAutoConfiguration、
SecurityFilterAutoConfiguration这四个配置类,接下来的文章我们将围绕这四个配置类分析spring-security究竟为我们做了哪些自动配置。