专栏名称: 码农小胖哥
技术公众号:码农小胖哥
目录
相关文章推荐
51好读  ›  专栏  ›  码农小胖哥

Spring Security 实战干货:Spring Boot 中的 Spring Security 自动配置初探

码农小胖哥  · 掘金  ·  · 2019-10-14 11:57

正文

阅读 18

Spring Security 实战干货:Spring Boot 中的 Spring Security 自动配置初探

1. 前言

我们在前几篇对 Spring Security 的用户信息管理机制,密码机制进行了探讨。我们发现 Spring Security Starter 相关的 Servlet 自动配置都在 spring-boot-autoconfigure-2.1.9.RELEASE (当前 Spring Boot 版本为 2.1.9.RELEASE ) 模块的路径 org.springframework.boot.autoconfigure.security.servlet 之下。其实官方提供的Starter组件的自动配置你都能在 spring-boot-autoconfigure-2.1.9.RELEASE 下找到。今天我们进一步来解密 Spring Security Spring Boot 的配置和使用。

2. Spring Boot 下 Spring Security 的自动配置

我们可以通过 org.springframework.boot.autoconfigure.security.servlet 路径下找到 Spring Security 关于 Servlet 的自动配置类。我们来大致了解一下。

2.1 SecurityAutoConfiguration

 package org.springframework.boot.autoconfigure.security.servlet;
 
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.security.SecurityDataConfiguration;
 import org.springframework.boot.autoconfigure.security.SecurityProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 import org.springframework.security.authentication.AuthenticationEventPublisher;
 import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
 
 /**
  * {@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 })
 public class SecurityAutoConfiguration {
 
 	@Bean
 	@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
 	public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
 		return new DefaultAuthenticationEventPublisher(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 ,也就是说发生不同认证的异常使用不同处理策略。

2.2 SpringBootWebSecurityConfiguration

 @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 {
 
 	}
 
 }
复制代码

这个类是Spring Security 对 Spring Boot Servlet Web 应用的默认配置。核心在于 WebSecurityConfigurerAdapter 适配器。从 @ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class) 我们就能看出 WebSecurityConfigurerAdapter 是安全配置的核心。 默认情况下 DefaultConfigurerAdapter 将以 SecurityProperties.BASIC_AUTH_ORDER -5 ) 的顺序注入 Spring IoC 容器,这是个空实现。如果我们需要个性化可以通过继承 WebSecurityConfigurerAdapter 来实现。我们会在以后的博文重点介绍该类。

2.3 WebSecurityEnablerConfiguration

 @Configuration
 @ConditionalOnBean(WebSecurityConfigurerAdapter.class)
 @ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
 @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
 @EnableWebSecurity
 public class WebSecurityEnablerConfiguration {
 
 }
复制代码

该配置类会在 SpringBootWebSecurityConfiguration 注入 Spring IoC 容器后启用 @EnableWebSecurity 注解。也就是说 WebSecurityEnablerConfiguration 目的仅仅就是在某些条件下激活 @EnableWebSecurity 注解。那么这个注解都有什么呢?

3. @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 {
 
 	/**
 	 * Controls debugging support for Spring Security. Default is false.
 	 * @return if true, enables debug support with Spring Security
 	 */
 	boolean debug() default false;
 } 
复制代码

@Enable* 这类注解都是带配置导入的注解。通过导入一些配置来启用一些特定功能。 @EnableWebSecurity 导入了 WebSecurityConfiguration SpringWebMvcImportSelector OAuth2ImportSelector 以及启用了 @EnableGlobalAuthentication 注解。

3.1 WebSecurityConfiguration

该配置类 WebSecurityConfiguration 使用一个 WebSecurity 对象基于用户指定的或者默认的安全配置,你可以通过继承 WebSecurityConfigurerAdapter 或者实现 WebSecurityConfigurer 来定制 WebSecurity 创建一个 FilterChainProxy Bean来对用户请求进行安全过滤。这个 FilterChainProxy 的名称就是 WebSecurityEnablerConfiguration 上的 BeanIds.SPRING_SECURITY_FILTER_CHAIN 也就是 springSecurityFilterChain ,它是一个Filter,最终会被作为Servlet过滤器链中的一个Filter应用到Servlet容器中。安全处理的策略主要是过滤器的调用顺序。 WebSecurityConfiguration 最终会通过 @EnableWebSecurity 应用到系统。

源码分析:

 package org.springframework.security.config.annotation.web.configuration;
 
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
 import javax.servlet.Filter;
 
 import org.springframework.beans.factory.BeanClassLoaderAware;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.DependsOn;
 import org.springframework.context.annotation.ImportAware;
 import org.springframework.core.OrderComparator;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.AnnotationAttributes;
 import org.springframework.core.annotation.AnnotationUtils;
 import org.springframework.core.annotation.Order;
 import org.springframework.core.type.AnnotationMetadata;
 import org.springframework.security.access.expression.SecurityExpressionHandler;
 import org.springframework.security.config.annotation.ObjectPostProcessor;
 import org.springframework.security.config.annotation.SecurityConfigurer;
 import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
 import org.springframework.security.config.annotation.web.builders.WebSecurity;
 import org.springframework.security.context.DelegatingApplicationListener;
 import org.springframework.security.web.FilterChainProxy;
 import org.springframework.security.web.FilterInvocation;
 import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
 import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
 
 
 /**
  * Spring Web Security 的配置类 : 
  *  1. 使用一个 WebSecurity 对象基于安全配置创建一个 FilterChainProxy 对象来对用户请求进行安全过滤。 
  *  2. 也会暴露诸如 安全SpEL表达式处理器 SecurityExpressionHandler 等一些类。
  *   
  * @see EnableWebSecurity
  * @see WebSecurity
  *
  * @author Rob Winch
  * @author Keesun Baik
  * @since 3.2
  */
 @Configuration
 public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
 	private WebSecurity webSecurity;
  // 是否启用了调试模式,来自注解 @EnableWebSecurity 的属性 debug,缺省值 false
 	private Boolean debugEnabled;
 
 	private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
 
 	private ClassLoader beanClassLoader;
 
 	@Autowired(required = false)
 	private ObjectPostProcessor<Object> objectObjectPostProcessor;
   /**
    *
    * 代理监听器 应该时监听 DefaultAuthenticationEventPublisher 的一些处理策略
    */   
 	@Bean
 	public static DelegatingApplicationListener delegatingApplicationListener() {
 		return new DelegatingApplicationListener();
 	}
    /**
     *
     * 安全SpEL表达式处理器 SecurityExpressionHandler 缺省为一个 DefaultWebSecurityExpressionHandler
     */   
 	@Bean
 	@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
 	public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
 		return webSecurity.getExpressionHandler();
 	}
 
 	/**
 	 *  Spring Security 核心过滤器  Spring Security Filter Chain  , Bean ID 为 springSecurityFilterChain
 	 * @return






请到「今天看啥」查看全文