当前位置: 代码迷 >> 综合 >> SpringSecurity------WebSecurityConfiguration配置类
  详细解决方案

SpringSecurity------WebSecurityConfiguration配置类

热度:99   发布时间:2023-12-20 23:13:53.0

SpringSecurity------WebSecurityConfiguration配置类

  • 一、WebSecurityConfiguration是怎样被加载的
  • 二、WebSecurityConfiguration主要做了什么
  • 三、WebSecurityConfiguration的源码分析
    • 1、属性字段
    • 2、核心方法
      • 内部初始化WebSecurity的setFilterChainProxySecurityConfigurer()方法
      • 内部构建FilterChainProxy的springSecurityFilterChain()方法
    • 3、使用@Autowired注入了一些Bean
    • 4、使用@Bean初始化一些Bean
    • 5、实现的接口方法
    • 6、一个内部类

一、WebSecurityConfiguration是怎样被加载的

通过在配置类上加入@EnableWebSecurity注解来引入WebSecurityConfiguration.class配置类,源码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({
     WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
    boolean debug() default false;
}

我们可以看到在注解@EnableWebSecurity上使用@Import()引入了WebSecurityConfiguration.class配置类。

二、WebSecurityConfiguration主要做了什么

简单的说,这个类的作用就是用来创建FilterChainProxy,FilterChainProxy是一个Servlet Filter,他是一组SecurityFilterChain的代理,用于管理这些SecurityFilterChain

首先,FilterChainProxy是SpringSecurity提供的基于Servlet标准的过滤器,他可以被Servlet容器使用。SecurityFilterChain是SpringSecurity提供的自有安全过滤器链,他不是基于Servlet标准的过滤器。SpringSecurity使用FilterChainProxy管理一组SecurityFilterChain,这样就可以通过代理的方式将SpringSecurity自有的滤器链应用于Servlet容器。

然后,当前配置类会加载容器中所有的WebSecurityConfigurer配置类、WebSecurityCustomizer配置类(5.4以后)、SecurityFilterChain过滤器链。这些都是用于配置生成一个WebSecurity。

接着,当WebSecurity实例被构建完成后,会使用WebSecurity去创建一个FilterChainProxy,这个FilterChainProxy会被放到容器中。

三、WebSecurityConfiguration的源码分析

1、属性字段

//SpringSecurity的FilterChainProxy的建造器
private WebSecurity webSecurity;
//标识是否开启debug模式,来自注解@EnableWebSecurity的属性debug
private Boolean debugEnabled;
//SpringSecurity的配置类列表
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
//SpringSecurity的核心过滤器链的列表
private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
//用户自定义WebSecurity的配置类列表(5.4版本之后新增的配置类)
private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();
//一个类加载器
private ClassLoader beanClassLoader;
//对象后处理器(这里依赖注入的是AutowireBeanFactoryObjectPostProcessor)
@Autowired(required = false)
private ObjectPostProcessor<Object> objectObjectPostProcessor;

2、核心方法

内部初始化WebSecurity的setFilterChainProxySecurityConfigurer()方法

在这个方法中会创建一个WebSecurity实例,然后将注解参数列表中@Value()注解引入的所有WebSecurityConfigurer配置设置到WebSecurity实例中。同时初始化了当前配置类的两个属性值webSecurity和webSecurityConfigurers。

@Value()引入方式就是AutowiredWebSecurityConfigurersIgnoreParents的方法调用。

/** * 获取并设置容器中已经加载的所有WebSecurityConfigurer实例用于配置,初始化一个WebSecurity * * @param objectPostProcessor 后处理对象(AutowireBeanFactoryObjectPostProcessor) * @param webSecurityConfigurers 用户自定义的配置(WebSecurityConfigurerAdapter的子类或是WebSecurityConfigurer接口的实现) * @throws Exception */
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)throws Exception {
    /*** 1、初始化一个WebSecurity实例,并其赋值到类属性webSecurity上*/this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));/*** 2、设置是否开启debug模式*/if (this.debugEnabled != null) {
    this.webSecurity.debug(this.debugEnabled);}/*** 3、根据@Order注解排序,然后检测配置排序是否有重复*/webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);Integer previousOrder = null;Object previousConfig = null;for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
    //AnnotationAwareOrderComparator是本类中的一个内部类,下面有介绍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;}/*** 4、将配置添加到webSecurity中*/for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
    this.webSecurity.apply(webSecurityConfigurer);}/*** 5、将配置类列表复制到类属性webSecurityConfigurers上*/this.webSecurityConfigurers = webSecurityConfigurers;
}

内部构建FilterChainProxy的springSecurityFilterChain()方法

首先,在这个方法中首先会判断是否有用户自定义的WebSecurityConfigurer和SecurityFilterChain:

  • 如果这两种自定义实例同时存在则会抛出异常。
  • 如果只存在SecurityFilterChains,将其设置到已经被创建的webSecurity中。
  • 如果这两个自定义实例都不存在,则会创建一个默认的WebSecurityConfigurerAdapter配置,并将其设置到已经被创建的webSecurity中。

然后,调用webSecurity.build()方法创建一个FilterChainProxy,这个Bean会被放到容器中

/*** 创建FilterChainProxy代理* * @return* @throws Exception*/
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
    /*** 1、判断是否有自定义配置类*/boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();/*** 2、判断是否有自定义配置的SecurityFilterChain*/boolean hasFilterChain = !this.securityFilterChains.isEmpty();/*** 3、自定义的WebSecurityConfigurerAdapter和SecurityFilterChain不能同时存在*/Assert.state(!(hasConfigurers && hasFilterChain),"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");/*** 4、如果没有配置类且没有SecurityFilterChain,创建一个默认配置,并添加到webSecurity*/if (!hasConfigurers && !hasFilterChain) {
    WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
    });this.webSecurity.apply(adapter);}/*** 5、设置webSecurity的拦截器链和拦截器*/for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
    this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);for (Filter filter : securityFilterChain.getFilters()) {
    if (filter instanceof FilterSecurityInterceptor) {
    this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);break;}}}/*** 6、用户的一些自定义配置webSecurity*/for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
    customizer.customize(this.webSecurity);}/*** 7、以上配置完成webSecurity后调用WebSecurity.build()方法创建FilterChainProxy*/return this.webSecurity.build();
}

FilterChainProxy的创建过程

3、使用@Autowired注入了一些Bean

注入容器中所有用户自定义的WebSecurityCustomizer

/** * 注入容器中所有用户自定义的WebSecurityCustomizer,用于自定义WebSecurity * * @param webSecurityCustomizers */
@Autowired(required = false)
void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) {
    webSecurityCustomizers.sort(AnnotationAwareOrderComparator.INSTANCE);this.webSecurityCustomizers = webSecurityCustomizers;
}

注入容器中所有的SecurityFilterChain

/** * 依赖注入所有的SecurityFilterChain * * @param securityFilterChains */
@Autowired(required = false)
void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
    securityFilterChains.sort(AnnotationAwareOrderComparator.INSTANCE);this.securityFilterChains = securityFilterChains;
}

4、使用@Bean初始化一些Bean

/*** 初始化一个AutowiredWebSecurityConfigurersIgnoreParents实例,用于加载容器中的所有WebSecurityConfigurer实例* * @param beanFactory* @return*/
@Bean
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
    return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
}
/*** 一个事件监听器的管理器,用于管理所有的鉴权事件* * @return*/
@Bean
public static DelegatingApplicationListener delegatingApplicationListener() {
    return new DelegatingApplicationListener();
}
/*** 权限表达式的支持* * @return*/
@Bean
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
    return this.webSecurity.getExpressionHandler();
}
/*** 权限评估器。对于JSP-tag支持是必须的* * @return*/
@Bean
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public WebInvocationPrivilegeEvaluator privilegeEvaluator() {
    return this.webSecurity.getPrivilegeEvaluator();
}
/*** 钩子接口,用于修改BeanFactory* * @return*/
@Bean
public static BeanFactoryPostProcessor conversionServicePostProcessor() {
    return new RsaKeyConversionServicePostProcessor();
}

5、实现的接口方法

这个方法是接口ImportAware的方法,当前配置类是通过@EnableWebSecurity注解上的@Import注解引入的,实现该接口的方法使得当前配置类可以获取到@EnableWebSecurity的debug属性值

/*** 获取注解的日志级别并设置(ImportAware接口的方法)*/
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
    Map<String, Object> enableWebSecurityAttrMap = importMetadata.getAnnotationAttributes(EnableWebSecurity.class.getName());AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap);this.debugEnabled = enableWebSecurityAttrs.getBoolean("debug");if (this.webSecurity != null) {
    this.webSecurity.debug(this.debugEnabled);}
}

这个接口可以使得当前配置类获取到加载他的类加载器

/*** 设置类加载器(BeanClassLoaderAware接口的方法)*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
    this.beanClassLoader = classLoader;
}

6、一个内部类

用于获取类上的@Order注解,并提供比较的功能

/*** 获取类上的Order注解的值* * @author dongyaowei* @date 2020年12月22日*/
private static class AnnotationAwareOrderComparator extends OrderComparator {
    private static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();@Overrideprotected 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;}
}
  相关解决方案