• SpringSecurity - 启动流程分析(一)


    概述

    SpringBoot - 集成 SpringSecurity 这篇文章中,我们知道只要在配置类上加上 @EnableWebSecurity 注解,就可以使我们的应用有一个默认配置的安全校验。接下我们就以 @EnableWebSecurity 为入口跟踪一下 Spring 在底层为我们做了哪些工作。

    @EnableWebSecurity

    @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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @EnableWebSecurity 使我们拥有了 SpringSecurity 的能力,并为 IoC 容器 中导入了几个配置类,比较重要的一个配置是:WebSecurityConfiguration,我们来看一下 WebSecurityConfiguration 为我们做了哪些工作

    WebSecurityConfiguration

    这里忽略了一些非主流程的代码,我们只需要关心重要流程

    @Configuration(proxyBeanMethods = false)
    public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
    
    	// 在 setFilterChainProxySecurityConfigurer 方法中初始化
    	private WebSecurity webSecurity;
    
    	private Boolean debugEnabled;
    
    	private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
    
    	private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
    
    	private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();
    
    	private ClassLoader beanClassLoader;
    
    	@Autowired(required = false)
    	private ObjectPostProcessor<Object> objectObjectPostProcessor;
    
    	@Bean
    	@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    	public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
    		return this.webSecurity.getExpressionHandler();
    	}
    
    	/**
    	 * Creates the Spring Security Filter Chain
    	 * @return the {@link Filter} that represents the security filter chain
    	 * @throws Exception
    	 */
    	@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    	public Filter springSecurityFilterChain() throws Exception {
    		// 如果我们自定义了配置类,这里就为 true
    		boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
    		// 默认 securityFilterChain 为空,所以这里为 false
    		boolean hasFilterChain = !this.securityFilterChains.isEmpty();
    		Assert.state(!(hasConfigurers && hasFilterChain),
    				"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
    		if (!hasConfigurers && !hasFilterChain) {
    			WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
    					.postProcess(new WebSecurityConfigurerAdapter() {
    					});
    			this.webSecurity.apply(adapter);
    		}
    		for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
    			this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
    			for (Filter filter : securityFilterChain.getFilters()) {
    				if (filter instanceof FilterSecurityInterceptor) {
    					this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
    					break;
    				}
    			}
    		}
    		// WebSecurity 的一些自定义配置
    		for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
    			customizer.customize(this.webSecurity);
    		}
    		// 最后调用 WebSecurity 的 build 方法(重点)!!!
    		// 整篇文章都在讲这个 build 方法,截止到文章末尾,这个方法也就走完了
    		return this.webSecurity.build();
    	}
    
    	 // 设置实例的 WebSecurity 属性,以及 webSecurityConfigurers
    	@Autowired(required = false)
    	public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
    			// 获取 WebSecurityConfigurers,配置类集合
    			@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
    			throws Exception {
    			// 先创建一个 WebSecurity 对象
    		this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
    		if (this.debugEnabled != null) {
    			this.webSecurity.debug(this.debugEnabled);
    		}
    		// 对配置类集合进行排序
    		webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
    		...
    		
    		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
    			// 将配置类中的信息加入到 WebSecurity 中
    			this.webSecurity.apply(webSecurityConfigurer);
    		}
    		this.webSecurityConfigurers = webSecurityConfigurers;
    	}
    
    	// 这里的 securityFilterChains 为 null
    	@Autowired(required = false)
    	void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
    		// 设置 securityFilterChains  属性
    		this.securityFilterChains = securityFilterChains;
    	}
    
    	// 这里的 webSecurityCustomizers 也为 null
    	@Autowired(required = false)
    	void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) {
    		this.webSecurityCustomizers = webSecurityCustomizers;
    	}
    
    	// 获取配置类集合:WebSecurityConfigurers
    	@Bean
    	public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
    			// 这里会自动注入:ConfigurableListableBeanFactory
    			ConfigurableListableBeanFactory beanFactory) {
    		return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
    	}
    
    	...
    }
    
    • 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

    我们首先查看一下 AutowiredWebSecurityConfigurersIgnoreParents

    AutowiredWebSecurityConfigurersIgnoreParents

    public final class AutowiredWebSecurityConfigurersIgnoreParents {
    
    	private final ConfigurableListableBeanFactory beanFactory;
    
    	AutowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
    		Assert.notNull(beanFactory, "beanFactory cannot be null");
    		this.beanFactory = beanFactory;
    	}
    
    	@SuppressWarnings({ "rawtypes", "unchecked" })
    	public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
    		List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
    		// 获取容器中类型为:WebSecurityConfigurer 的 Bean
    		Map<String, WebSecurityConfigurer> beansOfType = this.beanFactory.getBeansOfType(WebSecurityConfigurer.class);
    		for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
    			webSecurityConfigurers.add(entry.getValue());
    		}
    		return webSecurityConfigurers;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    通过 Debug 可以看到,getWebSecurityConfigurers 方法返回的就是我们继承自 WebSecurityConfigurerAdapter 的自定义配置类。

    核心流程WebSecurityConfiguration 中的 springSecurityFilterChain() 方法,创建了一个名为 springSecurityFilterChain 的 Bean,同时如果我们没有自定义配置的话,会初始化一个 WebSecurityConfigurerAdapter 作为 WebSecurity

    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    public Filter springSecurityFilterChain() throws Exception {
    	boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
    	boolean hasFilterChain = !this.securityFilterChains.isEmpty();
    	Assert.state(!(hasConfigurers && hasFilterChain),
    			"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
    	if (!hasConfigurers && !hasFilterChain) {
    		// 没有自定义配置类的话,会初始化一个 WebSecurityConfigurerAdapter
    		WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
    				.postProcess(new WebSecurityConfigurerAdapter() {
    				});
    		this.webSecurity.apply(adapter);
    	}
    	...
    
    	// 核心流程,返回一个 Filter
    	return this.webSecurity.build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    接下来会调用 WebSecuritybuild() 方法,来建立一个 Filter 对象对我们的请求进行拦截,从 Spring 官方文档 中我们知道,这里的 Filter 并不是 Servlet 中一个普通的 Filter 这么简单,这个 Filter 是一个代理的 FilterDelegatingFilterProxy),里面还会有过滤器链(SecurityFilterChain

    在这里插入图片描述

    AbstractConfiguredSecurityBuilder

    在查看 WebSecurity 中的 build 方法之前,我们先来看一下 apply 方法,入参在没有自定义配置的时候是 WebSecurityConfigurerAdapter

    // AbstractConfiguredSecurityBuilder
    
    public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
    	add(configurer);
    	return configurer;
    }
    
    private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
    	Assert.notNull(configurer, "configurer cannot be null");
    	Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
    			.getClass();
    	synchronized (this.configurers) {
    		if (this.buildState.isConfigured()) {
    			throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
    		}
    		List<SecurityConfigurer<O, B>> configs = null;
    		if (this.allowConfigurersOfSameType) {
    			configs = this.configurers.get(clazz);
    		}
    		configs = (configs != null) ? configs : new ArrayList<>(1);
    		configs.add(configurer);
    		// 保存配置类集合
    		this.configurers.put(clazz, configs);
    		if (this.buildState.isInitializing()) {
    			this.configurersAddedInInitializing.add(configurer);
    		}
    	}
    }
    
    • 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

    AbstractSecurityBuilder

    WebSecuritybuild() 方法:

    @Override
    public final O build() throws Exception {
    	if (this.building.compareAndSet(false, true)) {
    		this.object = doBuild();
    		return this.object;
    	}
    	throw new AlreadyBuiltException("This object has already been built");
    }
    
    // 由子类实现
    protected abstract O doBuild() throws Exception;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    // AbstractConfiguredSecurityBuilder
    
    // 第一次进入这个方法,`this.configurers` 应该是我们自定义的配置类,如果没有自定义配置类,那应该是 `WebSecurityConfigurerAdapter`
    @Override
    protected final O doBuild() throws Exception {
    	synchronized (this.configurers) {
    		this.buildState = BuildState.INITIALIZING;
    		beforeInit();
    		// 核心流程1
    		init();
    		this.buildState = BuildState.CONFIGURING;
    		beforeConfigure();
    		configure();
    		this.buildState = BuildState.BUILDING;
    		// 核心流程2
    		O result = performBuild();
    		this.buildState = BuildState.BUILT;
    		return result;
    	}
    }
    
    // init() 方法调用的是自定义配置类的 init() 方法
    private void init() throws Exception {
    	Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
    	for (SecurityConfigurer<O, B> configurer : configurers) {
    		// 核心流程,这里的 init 方法,走的是 WebSecurityConfigurerAdapter 中的 init 方法
    		configurer.init((B) this);
    	}
    	for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
    		configurer.init((B) this);
    	}
    }
    
    protected abstract O performBuild() throws Exception;
    
    • 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

    WebSecurity

    @Override
    protected Filter performBuild() throws Exception {
    	// 这里的 securityFilterChainBuilders 那里来的,还不能为空?
    	Assert.state(!this.securityFilterChainBuilders.isEmpty(),
    			() -> "At least one SecurityBuilder needs to be specified. "
    					+ "Typically this is done by exposing a SecurityFilterChain bean "
    					+ "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
    					+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()
    					+ ".addSecurityFilterChainBuilder directly");
    	int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
    	List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
    	for (RequestMatcher ignoredRequest : this.ignoredRequests) {
    		securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
    	}
    	// 这里的 securityFilterChainBuilders 经过上面的 init 方法之后,里面是一个 HttpSecurity
    	for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
    		// 这里通过 HttpSecurity 的 build 方法,转换为了 SecurityFilterChain,在源码中可以看到 build 方法最终返回的是 DefaultSecurityFilterChain
    		securityFilterChains.add(securityFilterChainBuilder.build());
    	}
    
    	// 把上面收集到的 securityFilterChains 赋值给 FilterChainProxy
    	FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
    	if (this.httpFirewall != null) {
    		filterChainProxy.setFirewall(this.httpFirewall);
    	}
    	if (this.requestRejectedHandler != null) {
    		filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
    	}
    	filterChainProxy.afterPropertiesSet();
    
    	Filter result = filterChainProxy;
    	if (this.debugEnabled) {
    		this.logger.warn("\n\n" + "********************************************************************\n"
    				+ "**********        Security debugging is enabled.       *************\n"
    				+ "**********    This may include sensitive information.  *************\n"
    				+ "**********      Do not use in a production system!     *************\n"
    				+ "********************************************************************\n\n");
    		result = new DebugFilter(filterChainProxy);
    	}
    	this.postBuildAction.run();
    	return result;
    }
    
    • 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

    这里保留一个疑问:performBuild() 方法中 securityFilterChainBuilders 哪里来的?

    WebSecurityConfigurerAdapter

    WebSecurity 中的 build() 方法会调用 WebSecurityConfigurerAdapter 类的 init() 方法:

    @Override
    public void init(WebSecurity web) throws Exception {
    	// 获取 HttpSecurity
    	HttpSecurity http = getHttp();
    	// 核心流程 addSecurityFilterChainBuilder,就是把 HttpSecurity 给添加到了 WebSecurity 的 securityFilterChainBuilder 属性中
    	web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
    		FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
    		web.securityInterceptor(securityInterceptor);
    	});
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通过 getHttp() 方法获取到 HttpSecurity 对象之后,使用 addSecurityFilterChainBuilderWebSecurity 中的 securityFilterChainBuilders 变量进行了赋值,在 WebSecurity 中的 performBuild() 方法中又把这个 securityFilterChainBuilders 转换为了 FilterChainProxy,从这里知道,我们会在 HttpSecurity 中组合 Filters。

    // WebSecurity
    
    public WebSecurity addSecurityFilterChainBuilder(
    	SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
    	this.securityFilterChainBuilders.add(securityFilterChainBuilder);
    	return this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    到目前为止,虽然还没有把整个的流程给分析完,但是已经基本上把前期的准备工作,和一些 Bean 的创建以及关联说了一下,整个过程如下面的流程图:

    在这里插入图片描述

  • 相关阅读:
    Worthington丨Worthington 蛋白酶K(Proteinase K)说明书
    OpenGL - Parallax Mapping
    企业架构LNMP学习笔记9
    R语言lavaan结构方程模型(SEM)实践技术应用
    鼠标划过改变子元素的属性 vue
    有人知道这个动作模型是哪里的吗?叫什么?
    网络正常,微信正常登录,谷歌浏览器无法正常打开(100%解决)
    (三)Python Range循环
    java springBoot实现RabbitMq消息队列 生产者,消费者
    【继承之extends关键字和super关键字】
  • 原文地址:https://blog.csdn.net/qiaohao0206/article/details/125863741