我们知道SpringSecurity在Spring项目中是提供安全措施的,那么在web开发中我们一般通过Filter来保护web资源,同样,SpringSecurity也是通过一系列Filter来保护我们的Web资源,但是,和平时使用的不同的是,这些Filter不需要我们直接实现,在We开发中的常用的Filter已经在框架中实现了,我们需要做的就是进行相应的配置即可,这些已经实现的filter将会被组建成一个FilterChain,在项目启动的时候,将启动这个过滤器链来为我们的项目提供安全服务;
所以,在研究SpringSecurity框架原理的时候就是在研究这个FilterChain是怎样在项目启动的时候组建起来的,而我们自己的配置又是通过怎样的机制加载进去的;以及后续的学习中,这些Filters具体的工作流程是什么 ;
第一个问题,FilterChain的创建流程——
在这里,我们需要开始接触SpringSecurity相关的代码(只是很小的一部分):
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
在项目中,我们通过声明上面的类来为我们的项目引入SpringSecurity的安全服务,具体来说,是一个注解@EnableWebSecurity和继承的一个类WebSecurityConfigureAdapter;
SPringSecurity就是从这两样东西开始——
首先来看一下@EnableWebSecurity注解:
官方通过注释说明:将此注释添加到具有@configuration注解的类上以使用SpringSecurity;也就是说,是这个注解为我们引入了SpringSecurity,现在记住这点就可以了,至于是通过什么机制引入的我们之后再看;
其次,我们来看看另一个——WebSecurityConfigureAdapter类,
public abstract class WebSecurityConfigurerAdapter implements
WebSecurityConfigurer
通过注释我们可以知道:为创建websecurityconfigurer实例提供了一个方便的基类,具体可以通过重写方法进行定制其实现。
也就是说,这个类的作用是方便我们通过继承他并重写其中的相关方法来定制我们自己websecurityconfigurer;至于websecurityconfigurer,看名字就是知道是用来配置Filter的;
所以,要使用spring security,首先我们需要继承websecurityconfigureadapter类并重写其中相关的方法类为我们的项目进行配置;同时在这个类上要添加@configuration注解和@Enable web Security注解来引入spring security的支持;
所以,到此为止,具体是怎么创建出FilterChain的呢?我们直接来看对应创建的源码——
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List 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);
上面的代码可以看到FilterChain的创建主要依赖两个对象——ignoredRequest和securityfilterchainbuilder,
分别通过
new DefaultSecurityFilterChain(ignoredRequest)
和
securityFilterChainBuilder.build()
可分别创建一个FilterChain,然后“add”进“securityFilterChains”中,具体的实现我们暂且不去理会,主要来大概看一下这两中创建方式,
第一种大概可以看出是以ignoredRequest对象为参数“new”了一个default的FilterChain——创建出的应该是一个默认配置的FilterChain,(我们暂且这样理解)
而第二种调用的是filterchain的“builder”方法,也就是通过他的构造器build出了一个FilterChain;
这两种方式穿件有什么不同的地方或者有什么联系,我们之后再说,在这里,我们应该知道的是我们所需要的这过滤器链是在哪、通过什么样的方式创建出来的,看过这里的创建代码,对这个过程有一个大概的了解对之后的分析将会带来很大的帮助;
同时,在上面的代码中应该注意到一个细节——创建的FilterChain加入到了一个列表中,也就说,允许为我们的项目创建多个FilterChain;还有就是,最后创建的并不是真正的filter组成的链,而是一个“proxy”,是一个代理;
到此为止,我们知道创建FilterChain有两种方式:
new一个默认的实现,或者通过构建器构建一个,在这里我们很容易猜想到的是,通过构建器securityFilterChainBuilder构建的FilterChain应该是与默认实现相对的——自定义配置的实现,所以说,我们之前提到的自定义配置是通过构建器来实现的,那么下面就来看一看这个过程的具体实现流程,
首先,securityFilterChainBuilder是什么?
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http)
上面的代码中通过getHttp方法返回一个http对象,然后将这个http对象作为参数传递给了addSecurityFilterChainBuilder方法,再来看这个方法:
public WebSecurity addSecurityFilterChainBuilder(
SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder) {
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
return this;
}
代码注释中对这个方法的说明:
现在很明了的是,http对象就是一个securityFilterChainBuilder,通过addsecurityFilterChainBuilder()方法将其加入到了securityFilterChainBuilders列表中,而这个列表我们已经在上面创建FilterChain的代码中见过了,就是一个用来存放securityFilterChainBuilder的列表;
所以说,这个通过getHttp()方法得到的http对象就是用来生成filterchain的构建器,
因此,接着来看关于getHttp()的代码 :
protected final HttpSecurity getHttp() throws Exception {
if (http != null) {
return http;
}
/*省略不必要的代码*/
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
sharedObjects);
configure(http);
return http;
}
上面的代码不必仔细阅读,直接看代码中关于这个方法的注释:
创建httpsecurity或返回当前实例
很假单的一句说明,这个方法的功能也和这个注释一样简单——直接返回一个http对象,如果没有的话则创建一个http对象然后返回,(这里要说明的是,该方法中直接返回的http对象是源自于该方法所属的类中的,在这里读者可能也会有疑惑,本文中所提及到的方法均没有说明其所属的类,在这里说明一下,未提及到具体的类是为了刚开始接触源码的同学逻辑产生混乱;以及这些需要记忆的类名会对理解造成困扰,而不提及方法所属的类对于我们理解FilterChain的创建过程并没有任何的影响,反而因为不会分散过多的注意力在类名和类之间的调用关系上而对创建的过程有一个更加清楚的了解,上面所提及到的代代码和所属的类将会在之后详细分析的时候一一解读;本篇文章只是让读者对SpringSecurity框架的原理和工作流程有一个整体把握)
现在,我们应该来看一下最后这个最重要的角色——http对象:
下面列出了该类中主要的属性和方法;但是也不用细看,分析中有对应的详细说明;
public final class HttpSecurity{
private final RequestMatcherConfigurer requestMatcherConfigurer;
private List filters = new ArrayList();
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
private FilterComparator comparator = new FilterComparator();
private ApplicationContext getContext();
public OpenIDLoginConfigurer openidLogin()
public HeadersConfigurer headers()
public CorsConfigurer cors()
public SessionManagementConfigurer sessionManagement()
public PortMapperConfigurer portMapper()
public JeeConfigurer jee()
public X509Configurer x509()
public RememberMeConfigurer rememberMe()
public ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests()
public RequestCacheConfigurer requestCache()
public ExceptionHandlingConfigurer exceptionHandling()
public SecurityContextConfigurer securityContext()
public ServletApiConfigurer servletApi()
public CsrfConfigurer csrf()
public LogoutConfigurer logout()
public AnonymousConfigurer anonymous()
public FormLoginConfigurer formLogin()
public ChannelSecurityConfigurer.ChannelRequestMatcherRegistry requiresChannel()
public HttpBasicConfigurer httpBasic()
protected void beforeConfigure()
protected DefaultSecurityFilterChain performBuild()
public HttpSecurity authenticationProvider(
AuthenticationProvider authenticationProvider)
public HttpSecurity userDetailsService(UserDetailsService userDetailsService)
private AuthenticationManagerBuilder getAuthenticationRegistry()
public HttpSecurity addFilterAfter(Filter filter, Class extends Filter> afterFilter)
public HttpSecurity addFilterBefore(Filter filter,
Class extends Filter> beforeFilter)
public HttpSecurity addFilter(Filter filter)
public HttpSecurity addFilterAt(Filter filter, Class extends Filter> atFilter)
public RequestMatcherConfigurer requestMatchers()
public HttpSecurity requestMatcher(RequestMatcher requestMatcher)
public HttpSecurity antMatcher(String antPattern)
public HttpSecurity regexMatcher(String pattern)
public final class MvcMatchersRequestMatcherConfigurer
private > C getOrApply(
C configurer)
}
先看注释:
http security类似于Spring Security在命名空间配置中的xml<和http>元素。
它为特定的HTTP请求配置基于Web的安全性。默认情况下,将应用于所有请求,但可以使用requestmatcher(requestmatcher就是上面所提到的第一种创建默认配置的filter chain时的对象参数ignoredrequest所属的类)或其他类似方法进行限制。
也是就是说,http就是一个配置类,配置的内容是该类中的各种方法对应的Filter,见名知意,读者可以大致浏览一下上面列出的方法,httpSecurity就是通过这些类来配置相应的过滤器的;可以明显的看出来,上面的各种配制方法的返回值是一个***configrer——也就是后面在创建filter chain时要用到的各种configurer就是通过http对象中的方法返回的;
以上便是Spring Security创建filterChain的逻辑过程,之后我们来看具体的实现流程是怎样的,也就是这些类之间的调用关系和SpringSecurity的启动流程,几乎所有的工作将会围绕这个流程的实现来进行,或扩展某个具体过程,或添加被我们省略掉的步骤;
http对象在那里创建?http到底包含什么内容?http对象是怎样作为filter chain的builder来创建filter chain的?详见下一篇文章:
SpringSecurit原理解读和使用教程(二)——spring security的启动流程