Spring Security的功能能够归纳为两部分,即认证和受权。html
认证就是一个用户使用令牌(最多见的是帐号和密码)登录,服务器验证这个用户的令牌是否有效。html5
受权则是认证以后,系统根据这个用户的信息判断他拥有哪些权限,能访问哪一种资源,能对资源进何种操做,并向他授予相关的权限,对没有权限访问的用户进行阻止。java
这里说的Spring Security是基于Servlet容器的。web
Spring Security的Servlet支持是基于Servlet的Filter
的。Filter能够对请求进行处理,但Filter通常会将处理好的请求交给FilterChain
中的下一个Filter,即一个个Filter按照相应的顺序组合起来造成了一个Filter链,从而达到对请求进行过滤/提早处理的效果。spring
当请求到达时,Servlet容器会初始化一个FilterChain
,并将请求传递到里面进行处理:api
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before the rest of the application
chain.doFilter(request, response); // invoke the rest of the application
// do something after the rest of the application
}
复制代码
通过一个个Filter处理后请求才到达Servlet处理并响应,因而可知,Filter在FilterChain
中组织的顺序很是重要。安全
由于Servlet容器跟Spring的IoC容器是两种不一样的容器,Servlet容器没法获知Spring容器中各类Bean(用户自定义Filter)的信息,也没法直接使用这些Bean(Filter),因此须要在二者间创建桥梁,使得咱们定义的Bean(Filter)可以被Servlet容器使用。服务器
Spring提供了一种叫DelegatingFilterProxy
的Filter实现。app
它像普通的Filter同样被插入到FilterChain
中,它的功能是将请求委托给Spring容器里的Bean Filter来处理,从而创建起Servlet容器和Spring容器之间的桥梁。性能
例如图中DelegatingFilterProxy
会在Spring容器中寻找Bean Filter0
,并将ServletRequest
和ServletResponse
传递过去:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// Lazily get Filter that was registered as a Spring Bean
// For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
Filter delegate = getFilterBean(someBeanName);
// delegate work to the Spring Bean
delegate.doFilter(request, response);
}
复制代码
DelegatingFilterProxy
的另外一个好处是它能够延迟加载Bean Filter实例,由于FilterChain
会在Servlet容器启动前初始化,这样能够提高Servlet容器启动的性能。
上面提到DelegatingFilterProxy
会将请求委托给Bean Filter,而其实这里的Bean Filter也不会直接处理请求,会将请求进一步转发,这个Bean Filter便是FilterChainProxy
。
FilterChainProxy
是Spring Security提供的特殊Filter,它会将请求委托到另外一种FilterChain
中,即Spring的FilterChain:SecurityFilterChain
。
咱们能够很天然地想到,SecurityFilterChain
中即是Spring的Bean Filter了,即SecurityFilter
:
这里的SecurityFilter
就是普通的Bean,他们能够识别本身能处理的请求并对请求处理,不然将请求传给链中的下一个Filter,例如最多见的UsernamePasswordAuthenticationFilter
能够识别处理基于表单的登录请求。
值得注意的是,SecurityFilterChain
能够有多条,能够根据不一样的请求来判断请求应该被传递到哪一个SecurityFilterChain
中:
好比符合/api/**
匹配模式的URL应该被传递到最上面的SecurityFilterChain
中,这个请求一旦匹配到了某个上游的SecurityFilterChain
,下游的SecurityFilterChain
就不会再进行匹配。
官方文档给出了按照Spring Security Filter排列顺序的列表:
ExceptionTranslationFilter
容许将AccessDeniedException
和AuthenticationException
异常转换为HTTP响应,从它的名字能够看到,它也是一个Filter,能够被插入到SecurityFilterChain
中,这是它的工做流程:
AuthenticationException
,则会被它捕获(见下面代码),并调用它的startAuthentication()
方法跳转进行认证。(图中的SecurityContextHolder
等几个东西属于认证功能部分,能够先不用管)AccessDeniedException
则对异常做出响应,通知用户禁止访问。从上面能够看到,Spring Security的功能是经过Filter来实现的。每一个Filter都是一个Bean,用户经过配置不一样的Filter或自行实现Filter来达到保护应用/认证/受权等目的,不一样的Filter组成了多个FilterChain,来实现不一样的要求。