/** * {@link EnableAutoConfiguration Auto-configuration} for Spring Security. * * @author Dave Syer * @author Andy Wilkinson * @author Madhura Bhave * @since 1.0.0 */ @Configuration @ConditionalOnClass(DefaultAuthenticationEventPublisher.class) @EnableConfigurationProperties(SecurityProperties.class) @Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class, SecurityDataConfiguration.class }) publicclassSecurityAutoConfiguration {
@Bean @ConditionalOnMissingBean(AuthenticationEventPublisher.class) public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) { returnnewDefaultAuthenticationEventPublisher(publisher); }
}
SecurityAutoConfiguration顾名思义安全配置类。该类引入(@import)了SpringBootWebSecurityConfiguration、WebSecurityEnablerConfiguration和SecurityDataConfiguration三个配置类。 让这三个模块的类生效。是一个复合配置,是 Spring Security 自动配置最重要的一个类之一。 Spring Boot 自动配置经常使用这种方式以达到灵活配置的目的,这也是我们研究 Spring Security 自动配置的一个重要入口 同时 SecurityAutoConfiguration还将DefaultAuthenticationEventPublisher作为默认的AuthenticationEventPublisher注入Spring IoC容器。如果你熟悉 Spring 中的事件机制你就会知道该类是一个 Spring 事件发布器。该类内置了一个HashMap<String, Constructor<? extends AbstractAuthenticationEvent>>维护了认证异常处理和对应异常事件处理逻辑的映射关系,比如账户过期异常AccountExpiredException对应认证过期事件AuthenticationFailureExpiredEvent ,也就是说发生不同认证的异常使用不同处理策略。
这个类是Spring Security 对 Spring Boot Servlet Web 应用的默认配置。核心在于WebSecurityConfigurerAdapter适配器。从@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)我们就能看出 WebSecurityConfigurerAdapter是安全配置的核心。 默认情况下DefaultConfigurerAdapter将以SecurityProperties.BASIC_AUTH_ORDER(-5)的顺序注入 Spring IoC 容器,这是个空实现。如果我们需要个性化可以通过继承WebSecurityConfigurerAdapter来实现。我们会在以后的博文重点介绍该类。
该配置类会在SpringBootWebSecurityConfiguration注入 Spring IoC 容器后启用@EnableWebSecurity注解。也就是说WebSecurityEnablerConfiguration目的仅仅就是在某些条件下激活@EnableWebSecurity注解。那么这个注解都有什么呢?
/** * Controls debugging support for Spring Security. Default is false. * @return if true, enables debug support with Spring Security */ booleandebug()defaultfalse; }
/** * Spring Security 核心过滤器 Spring Security Filter Chain , Bean ID 为 springSecurityFilterChain * @return the {@link Filter} that represents the security filter chain * @throws Exception */ @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public Filter springSecurityFilterChain()throws Exception { booleanhasConfigurers= webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty(); if (!hasConfigurers) { WebSecurityConfigurerAdapteradapter= objectObjectPostProcessor .postProcess(newWebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); } return webSecurity.build(); }
/** * * 用于模板 如JSP Freemarker 的一些页面标签按钮控制支持 * Creates the {@link WebInvocationPrivilegeEvaluator} that is necessary for the JSP * tag support. * @return the {@link WebInvocationPrivilegeEvaluator} * @throws Exception */ @Bean @DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public WebInvocationPrivilegeEvaluator privilegeEvaluator()throws Exception { return webSecurity.getPrivilegeEvaluator(); }
/** * * 用于创建web configuration的SecurityConfigurer实例, * 注意该参数通过@Value(...)方式注入,对应的bean autowiredWebSecurityConfigurersIgnoreParents * 也在该类中定义 * * @param objectPostProcessor the {@link ObjectPostProcessor} used to create a * {@link WebSecurity} instance * @param webSecurityConfigurers the * {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to * create the web configuration * @throws Exception */ @Autowired(required = false) publicvoidsetFilterChainProxySecurityConfigurer( ObjectPostProcessor<Object> objectPostProcessor, @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception { webSecurity = objectPostProcessor .postProcess(newWebSecurity(objectPostProcessor)); if (debugEnabled != null) { webSecurity.debug(debugEnabled); }
IntegerpreviousOrder=null; ObjectpreviousConfig=null; for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) { Integerorder= AnnotationAwareOrderComparator.lookupOrder(config); if (previousOrder != null && previousOrder.equals(order)) { thrownewIllegalStateException( "@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容器中获取所有的WebSecurityConfigurer bean。 * 这些WebSecurityConfigurer通常是由开发人员实现的配置类,并且继承自WebSecurityConfigurerAdapter * */ @Bean publicstatic AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents( ConfigurableListableBeanFactory beanFactory) { returnnewAutowiredWebSecurityConfigurersIgnoreParents(beanFactory); }
/** * A custom verision of the Spring provided AnnotationAwareOrderComparator that uses * {@link AnnotationUtils#findAnnotation(Class, Class)} to look on super class * instances for the {@link Order} annotation. * * @author Rob Winch * @since 3.2 */ privatestaticclassAnnotationAwareOrderComparatorextendsOrderComparator { privatestaticfinalAnnotationAwareOrderComparatorINSTANCE=newAnnotationAwareOrderComparator();
本文主要对 Spring Security 在 Spring Boot 中的自动配置一些机制进行了粗略的讲解。为什么没有细讲。因为从学习出发有些东西不是我们必须要深入了解的,但是又要知道一点点相关的知识。我们先宏观上有个大致的了解就行。所以在阅读本文一定不要钻牛角尖。粗略知道配置策略、加载策略和一些关键类的作用即可。在你对 Spring Security 有了进一步学习之后,回头认真来看这些配置类会有更深层的思考 从另一个方面该文也给你阅读 Spring 源码提供了一些思路,学会这些才是最重要的。