SpringSecurity原理分析(一)

编程

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.

至此 Spring Security 中最核心的 FilterChain就创建完毕了。

以上是 SpringSecurity原理分析(一) 的全部内容, 来源链接: utcz.com/z/519061.html

回到顶部