SpringSecurity的启动流程

本文详细介绍了SpringSecurity的启动流程,从SpringSecurity简介到其架构图,重点解析了WebSecurityConfiguration类中的配置过程,包括配置类的加载、init和configure方法的执行,以及AuthenticationManager和HttpSecurity的构建。通过理解这一流程,有助于深入掌握SpringSecurity的工作原理。
摘要由CSDN通过智能技术生成

SpringSecurity简介+启动流程

springSecurity简介

springSecurity是基于过滤器链的登录验证和权限校验框架,分为启动流程和执行流程,和实际应用三部部分,本章节介绍它的启动流程。后面陆续介绍它的执行流程和在生产实际中springSecurity+jwt的应用。

springSecurity的架构图

在这里插入图片描述
这是笔者在学习过程中绘画的关于spring-security的类图,springSecurity采用建造者(builder)设计模式,在securityBuild中定义了build方法,通过抽象类AbstractConfiguredSecurityBuilder进行通用实现,从而执行配置类(SecurityConfigurer)中的init方法和configure方法。在启动流程中会做详细介绍。

springSecurity的启动流程

在springSecurity中是通过WebSecurityConfiguration类进行安全相关的配置。该类中重点关注如下代码

@Autowired注解标注在类上在初始化对象的时候会调用该方法一次,并注入objectPostProcessor对象。@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()表示会执行autowiredWebSecurityConfigurersIgnoreParents类中的getWebSecurityConfigurers方法,并将执行结果注入给webSecurityConfigurers参数。在代码3中对该方法做了详细介绍,请在代码二中看此方法说明,也就是将我们的配置类放到List集合中返回。

代码1
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
			ObjectPostProcessor<Object> objectPostProcessor,
			@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
			throws Exception {
   
	    //通过objectPostProcessor生成WebSecurity对象
		webSecurity = objectPostProcessor
				.postProcess(new WebSecurity(objectPostProcessor));
		if (debugEnabled != null) {
   
			webSecurity.debug(debugEnabled);
		}
        //如果我们定义了多个配置类,可以实现Ordered接口,并重写getOrder对配置类进行排序,一般只定义一个配置类,所以不需要实现Ordered接口
		webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);

		Integer previousOrder = null;
		Object previousConfig = null;
		for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
   
			Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
			//在定义order排序编号过程中不允许重复,负责会报错
			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;
		}
		/**
		*webSecurty是SecurityBuilder类的实现类,apply方法是将配置类放到List集合中,便于执行SecurityBuilder中的build方法,从而
		*执行配置类中的init方法和configure方法,进行相关配置。apply方法请参考代码2
		*/
		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
   
			webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}

apply方法实际上执行的是add方法,此时的this变量指向WebSecurity。buildState变量用四种状态:buildState.UNBUILT(初始化状态前),INITIALIZING(初始化状态),BUILDING(构建中状态),BUILT(构建完成状态),会在执行后面的doBuild方法中体现。add方法实际上是将配置类对象放到webSecurity的configurers(linkedHashMap<Class,List>)集合中,换句话说将配置类(实现了SecurityConfigurer接口)放到实现了SecurityBuilder接口中的集合中。

代码2
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 (configurers) {
   
			if (buildState.isConfigured()) {
   
				throw new IllegalStateException("Cannot apply " + configurer
						+ " to already built object");
			}
			//allowConfigurersOfSameType 未初始化默认的状态是false,代表configurers Map中是否可以存在多个相同类型的配置类,
			//true代表可以,false不行,如果是false,代表Map中value集合的大小只能为1.
			List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
					.get(clazz) : null;
			if (configs == null) {
   
				configs = new ArrayList<>(1);
			}
			configs.add(configurer);
			//放到configurers Map集合中
			this.configurers.put(clazz, configs);
			//如果对象时初始化状态,则在configurersAddedInInitializing(List<SecurityConfigurer)也进行存放,此时是
			//未构建状态,应该configurersAddedInInitializing集合为空
			if (buildState.isInitializing()) {
   
				this.configurersAddedInInitializing.add(configurer);
			}
		}
	}

getWebSecurityConfigurers方法中获取实现了WebSecurityConfigurer接口的实现类,并添加到List集合列表返回。如果有用过SpringSecurty的同学就会发现,在使用springSecurity中,我们会定义一个安全配置类,继承WebSecurityConfigurerAdapter,并重写configure方法,用来表明对那些资源做拦截,或开启corf等相关配置。

代码3
final class AutowiredWebSecurityConfigurersIgnoreParents {
   

	@SuppressWarnings({
    "rawtypes", "unchecked" })
	public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
   
		List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
		Map<String, WebSecurityConfigurer> beansOfType = beanFactory
				.getBeansOfType(WebSecurityConfigurer.class);
		for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
   
			webSecurityConfigurers.add(entry.getValue());
		}
		return webSecurityConfigurers;
	}
}

通过上述代码在webSecurity对象中已经将配置类放入到WebSecurity的List集合中。最后执行webSecurity的build方法。

代码4
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
	public Filter springSecurityFilterChain() throws Exception {
   
		boolean hasConfigurers = webSecurityConfigurers != null
				&& !webSecurityConfigurers.isEmpty();
		//如果我们没有定义配置类,将会默认生成一个配置对象,进行默认的配置
		if (!hasConfigurers) {
   
			WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
					.postProcess(new WebSecurityConfigurerAdapter() {
   
					});
			webSecurity.apply(adapter)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值