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就创建完毕了。
来源:oschina
链接:https://my.oschina.net/zzxzzg/blog/4467351