Spring Security 原理分析(一)

原创
08/03 20:11
阅读数 47

Spring Security 初始化

在普通的spring mvc 框架中,我们需要

@Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter

手动添加 EnableWebSecurity 来启动 spring security,不过在Spring Boot中,我们不需要再写该注解。 因为,spring boot自动装配类 WebSecurityEnablerConfiguration 已经帮我们完成了该工作。

@Configuration( proxyBeanMethods = false )
@ConditionalOnBean({WebSecurityConfigurerAdapter.class})
@ConditionalOnMissingBean( name = {"springSecurityFilterChain"} )
@ConditionalOnWebApplication( type = Type.SERVLET )
@EnableWebSecurity
public class WebSecurityEnablerConfiguration { public WebSecurityEnablerConfiguration() { } }

再来看下 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;
}

关键点在 Import上,引入了 WebSecurityConfiguration 类。该类是security初始化的核心类,在细一些,可以定位到核心方法。

	@Autowired(required = false)
	public void setFilterChainProxySecurityConfigurer(
			ObjectPostProcessor<Object> objectPostProcessor,
			@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
			throws Exception {
		//初始化 WebSecurity
		webSecurity = objectPostProcessor
				.postProcess(new WebSecurity(objectPostProcessor));
		if (debugEnabled != null) {
			webSecurity.debug(debugEnabled);
		}
		//
		webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);

		Integer previousOrder = null;
		Object previousConfig = null;
		for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
			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;
		}
		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
			webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}

该方法使用 @Autowired 注解。 使用该注解方法会在对象被初始化后自动调用 。该方法的作用就是初始化一个 WebSecurity,并且将我们自定义的 WebSecurityConfigurerAdapter 类型对象存入 WebSecurity 。

之后,最重要的就是 通过方法 springSecurityFilterChain 初始化所有的filter并且组织成一个filter chain 该方法实际上就是调用 WebSecurity.build。

进一步剖析 WebSecurity.build

@Override
	protected final O doBuild() throws Exception {
		synchronized (configurers) {
			buildState = BuildState.INITIALIZING;

			beforeInit();
			init();

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
			configure();

			buildState = BuildState.BUILDING;

			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}

首先是init方法。该方法会调用所有 继承于 WebSecurityConfigurerAdapter 的类的init方法。 默认实现如下

public void init(final WebSecurity web) throws Exception {
		final HttpSecurity http = getHttp();
		web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
			FilterSecurityInterceptor securityInterceptor = http
					.getSharedObject(FilterSecurityInterceptor.class);
			web.securityInterceptor(securityInterceptor);
		});
	}

初始化了一个 HttpSecurity, 并将其放入 WebSecurity中。 HttpSecurity的初始化会设置很多默认的 AbstractHttpConfigurer 以及 创建一个 AuthenticationManager (configure(AuthenticationManagerBuilder auth) 会在这一步被调用)。 最后再把自定义的 AbstractHttpConfigurer 加入HttpSecurity中。 PS : 实际上 http.authorizeRequests() 这个链式调用就是向其中添加configurer的过程.

回到 WebSecurity.build 再之后就是调用所有 继承于 WebSecurityConfigurerAdapter 的类的 configure 方法.

最后,也是最重要的一步。调用 performBuild 生成最终的filter chain.

@Override
	protected Filter performBuild() throws Exception {
		...............
		int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
		List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
				chainSize);
		for (RequestMatcher ignoredRequest : ignoredRequests) {
			securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
		}
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
			securityFilterChains.add(securityFilterChainBuilder.build());
		}
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		if (httpFirewall != null) {
			filterChainProxy.setFirewall(httpFirewall);
		}
		filterChainProxy.afterPropertiesSet();

		Filter result = filterChainProxy;
		
	   .........
	   
		postBuildAction.run();
		return result;
	}

这里 securityFilterChainBuilders 就是我们刚刚创建的 HttpSecurity. 所以该方法实际上就是调用 HttpSecurity 的 build 方法。

HttpSecurity.build

HttpSecurity 和 webSecurity一样,都集成于 AbstractConfiguredSecurityBuilder 所以在调用流程方面基本上是一样的。

首先就是调用所有SecurityConfigurer 的init方法,然后再调用其中的 configure方法。从上面我们知道,在初始化HttpSecurity时,我们已经添加了很多的config在里面。拿 HttpBasicConfigurer 举例。

@Override
	public void configure(B http) {
		......
		http.addFilter(basicAuthenticationFilter);
	}

不管中间的业务代码,最终会在http上添加一个filter。

之后就是调用 performBuild

@Override
	protected DefaultSecurityFilterChain performBuild() {
		// 将所有filter排序
		filters.sort(comparator);
		//实例化一个 DefaultSecurityFilterChain 类型对象.
		return new DefaultSecurityFilterChain(requestMatcher, filters);
	}

回到WebSecurity层,httpSecurity的build方法已经运行完成,并返回了一个DefaultSecurityFilterChain. 最后 WebSecurity会将其包装成一个 FilterChainProxy 对象返回。 至此 Spring Security 中最核心的 FilterChain就创建完毕了。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
在线直播报名
返回顶部
顶部