SpringSecurity中文文档——Architecture

Spring Security 的 Serlvet支持是基于Servelt的过滤器实现的,下图展示了一个HTTP请求典型的分层处理过程。
SpringSecurity中文文档——Architecture
当客户端发送一个请求到应用时,容器会创建一个过滤器链FilterChain,包含Filter和基于请求URI处理HttpServletRequest 的Servlet。在SpringMVC应用中,Servlet是DispatcherServlet的一个实例。一个Servlet最多只能处理一个HttpServletRequest和HttpServletResponse。
However, more than one Filter can be used to:
但是,可以使用多个过滤器来:

  • 防止下游过滤器或Servlet被调用。在这种情况下,过滤器通常会写入HttpServletResponse。
  • 修改下游过滤器和Servlet使用的HttpServletRequest或HttpServletResponse。

DelegatingFilterProxy

Spring提供了一个名叫DelegatingFilterProxy的Filter实现,来桥接Servlet容器的生命周期和Spring的上下文ApplicationContext。Servlet容器允许使用自己的标准注册过滤器,但它不知道Spring定义的bean。DelegatingFilterProxy可以通过标准的Servlet容器机制注册,将所有工作委托给实现过滤器的Springbean。
SpringSecurity中文文档——Architecture
DelegatingFilterProxy从ApplicationContext中查找Bean Filter0,然后调用Bean Filter0。DelegatingFilterProxy的伪代码如下所示。

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实例。这一点很重要,因为容器需要在启动之前注册过滤器实例。然而,Spring通常使用ContextLoaderListener来加载Springbean,直到需要注册过滤器实例之后才会进行加载。
下面是DelegatingFilterProxy类的部分注释翻译:
web.xml通常包含一个DelegatingFilterProxy定义,指定的过滤器名称对应于Spring根应用程序上下文中的一个bean名称。然后,对过滤器代理的所有调用都将委托给Spring上下文中的bean,这是实现标准Servlet过滤器接口所必需的。

FilterChainProxy

Spring Security的Servlet支持包含在FilterChainProxy中。FilterChainProxy是Spring Security提供的一个特殊过滤器,它允许通过SecurityFilterChain委托给多个过滤器实例。由于FilterChainProxy是一个Bean,它通常被包装在一个DelegatingFilterProxy中。
SpringSecurity中文文档——Architecture

下面是FilterChainProxy类的部分注释翻译:
从3.1版开始,FilterChainProxy被配置SecurityFilterChain实例的列表,每个实例都包含一个{@link RequestMatcher}和一个用于匹配请求的过滤器列表。大多数应用程序只包含一个筛选器链,如果使用名称空间,则不必显式设置这些链。如果需要更细粒度的控制,可以使用名称空间元素。
SpringSecurity中文文档——Architecture
“filter1”, “filter2”, "filter3"是声明在应用上下文中Filter的实例名, 名称的顺序定义了过滤器执行的顺序。如上图所示,可以将fitlers配置成null, 来将请求完全从Security过滤器链排除掉。尽可能将特定请求url放到最前面进行配置,当一个pattern被匹配成功后,FilterChainProxy不会向后遍历其他的Filter配置来确定是否有更匹配的pattern。

HttpFirewall

用于拒绝潜在危险的请求,该实现被注入FilterChainProxy,并在通过过滤器链发送任何请求之前被调用。如果响应行为也应该受到限制,它还可以提供一个响应包装器。

SecurityFilterChain

FilterChainProxy使用SecurityFilterChain来确定应该为此请求调用哪些SpringSecurity的Filter。
SpringSecurity中文文档——Architecture
SecurityFilterChain中的Security Filter通常是bean,但它们是在FilterChainProxy中注册的,而不是在DelegatingFilterProxy中注册的。FilterChainProxy为直接向Servlet容器注册或删除FilterProxy提供了许多优势。首先,它为Spring Security的所有Servlet支持提供了一个起点。因此,如果您试图解决Spring Security的Servlet支持问题,那么在FilterChainProxy中添加调试点是一个很好的起点。

SecurityFilter

SecurityFilter通过SecurityFilterChain的API插入FilterChainProxy。SecurityFilter的顺序是很重要的。下面是SecurityFilter的调用顺序列表:

  • ChannelProcessingFilter
  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • CsrfFilter
  • LogoutFilter
  • OAuth2AuthorizationRequestRedirectFilter
  • Saml2WebSsoAuthenticationRequestFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • OAuth2LoginAuthenticationFilter
  • Saml2WebSsoAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • OAuth2AuthorizationCodeGrantFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

总结一下:
DelegatingFilterProxy是一个Filter的实现,它将一个SpringBean注册到Servlet,这个SpringBean就是FilterChainProxy。FilterChainProxy持有一个SecurityFilterChain的列表,可以决定请求使用哪一套Security过滤器链,SecurityFilterChain又包含了多个SecurityFilter,对一个请求进行处理。

Handling Security Exceptions

ExceptionTranslationFilter允许将AccessDeniedException和AuthenticationException转换为HTTP响应。ExceptionTranslationFilter作为Security Filter之一插入FilterChainProxy。ExceptionTranslationFilter作为Security Filters之一插入FilterChainProxy。

SpringSecurity中文文档——Architecture

  1. 首先,ExceptionTranslationFilter调用FilterChain.doFilter()来调用应用程序的其余部分。
  2. 如果用户未经身份验证或是身份验证异常,则启动身份验证。
    (1) 清空当前请求保存在SecurityContextHolder的身份信息。
    (2) 将当前请求保存在RequestCache中。当用户成功进行身份验证时,RequestCache用于重播原始请求。
    (3) AuthenticationEntryPoint用于身份认证失败时,启动身份校验例如重定向登录页、返回401等等、发送WWW认证头。在调用这个方法前,ExceptionTranslationFilter将请求的target URL填充到名为AbstractAuthenticationProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY的HttpSession属性。
  3. 否则,如果是AccessDeniedException,则拒绝访问。将调用AccessDeniedHandler来处理拒绝的访问。
  4. 如果应用程序不抛出AccessDeniedException或AuthenticationException,ExceptionTranslationFilter不做任何事。
上一篇:[分层图最短路][最短路变形]通信线路 AcWing340


下一篇:外源插件安装