当前位置: 代码迷 >> 综合 >> SpringSecurity------Filters Architecture(七)
  详细解决方案

SpringSecurity------Filters Architecture(七)

热度:16   发布时间:2023-12-20 23:14:42.0

SpringSecurity------Filters Architecture(七)

  • 一、Servlet Filters架构概括
  • 二、DelegatingFilterProxy 桥接Servlet Container和Spring ApplicationContext
  • 三、FilterChainProxy 代理SecurityFilterChain
  • 四、SecurityFilterChain 组织Security Filte
  • 五、Security Filter 过滤Request
  • 六、Handling Security Exceptions

一、Servlet Filters架构概括

Spring Security的Servlet支持是基于Servlet Filters的,下图显示了单个HTTP请求处理程序的典型分层:

HTTP请求处理程序的典型分层
客户端向应用程序发送一个请求,容器创建一个FilterChain,其中包含Filter和Servlet,FilterChain会根据请求URI处理HttpServletRequest。 在 Spring MVC应用程序中,Servlet是DispatcherServlet的一个实例。虽然一个Servlet只能处理一个HttpServletRequest和HttpServletResponse,但是一次请求中可以使用多个Filter

  • 阻止后续的Filter或是Servlet的调用,通常在这种Filter中会返回HttpServletResponse
  • 修改HttpServletRequest或HttpServletResponse之后,继续调用后续Filter和Servlet

传递给Filter的FilterChain赋予了Filter强大的功能:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // 之前做一些事情chain.doFilter(request, response); // 调用下一个过滤器// 之后再做一些事情
}

需要注意的是当前Filter只会影响后续Filter和Servlet,所以Filter的调用顺序是很重要的。

二、DelegatingFilterProxy 桥接Servlet Container和Spring ApplicationContext

Spring提供的DelegatingFilterProxy是一个Filter实现,用于桥接Servlet Container的生命周期和Spring ApplicationContext。Servlet Container使用自己的标准注册Filter,但是这些Filter发现不了Spring定义的Beans,DelegatingFilterProxy可以通过标准的Servlet Container机制注册,但是把所有的工作委托给实现了Filter的Spring Beans,下图是DelegatingFilterProxy如何匹配Filters和FilterChain:
DelegatingFilterProxy授权代理
DelegatingFilterProxy从ApplicationContext获取并调用Bean Filter0,下面是伪代码示例:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // 延时获取注册的Spring Bean,就好比上图中的Bean Filter0Filter delegate = getFilterBean(someBeanName);// 委托Spring Bean处理任务delegate.doFilter(request, response);
}

Servlet Container在启动之前需要注册Filter实例,然而,Spring通常使用ContextLoaderListener来加载Spring Beans,这些Spring Beans需要注册Filter之后才会被加载。

三、FilterChainProxy 代理SecurityFilterChain

Spring Security对Servlet的支持主要包含在FilterChainProxy中,FilterChainProxy是Spring Security提供的一个特殊的Filter,它可以通过SecurityFilterChain将委派多个Filter实例处理任务,FilterChainProxy是一个包裹在DelegatingFilterProxy中的Bean:
filterchainproxy

四、SecurityFilterChain 组织Security Filte

FilterChainProxy使用SecurityFilterChain来确定Request需要执行哪些Spring Security Filter:
securityfilterchain
SecurityFilterChain中的Security Filter都是典型的Beans,但是它们都是通过FilterChainProxy注册的,而不是使用DelegatingFilterProxy注册。FilterChainProxy注册机制的优势:

  • FilterChainProxy是Spring Security对Servlet支持的起点,调试应用程序的时候可以从这里开始。
  • FilterChainProxy是Spring Security功能的核心,它可以执行一些系统任务,例如清除SecurityContext以避免内存泄漏,利用 Spring Security 的HttpFirewall保护应用程序免受某些类型的攻击。
  • 它在决定何时应该调用SecurityFilterChain方面提供了更大的灵活性。 在Servlet容器中,仅根据URL调用Filter, 然而,FilterChainProxy可以通过利用RequestMatcher接口来确定基于HttpServletRequest中的任何东西的调用。
  • FilterChainProxy可以用来确定应该使用哪个SecurityFilterChain, 这允许为应用程序的不同部分提供完全独立的配置。

multi-securityfilterchain
存在多个SecurityFilterChain时,FilterChainProxy决定哪一个SecurityFilterChain将会被调用。只有第一个匹配成功的SecurityFilterChain会被调用。比如 /api/messages/ 请求,会首先匹配到SecurityFilterChain0的 /api/**,虽然它也可以匹配到SecurityFilterChainn,但只有SecurityFilterChain0会被执行。比如 /messages/ 请求,它不会匹配到SecurityFilterChain0的 /api/**,然后它会继续匹配 1、2、3......n-1,假如一直没有匹配成功,SecurityFilterChainn将会被执行。

注意,SecurityFilterChain0只配置了三个Security Filter实例,SecurityFilterChainn配置了四个Security Filter。 需要注意,每个SecurityFilterChain是唯一的,并且可以单独配置。如果应用程序希望Spring Security忽略某些请求,可以配置没有Security Filter的SecurityFilterChain。

五、Security Filter 过滤Request

Security Filter通过SecurityFilterChain API插入到FilterChainProxy中, Filter的顺序很重要。 通常不需要知道Spring Security的Filter的顺序, 然而,有时知道排序也是必要的,下面是一个完整的Spring安全过滤器排序列表:

  • 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

六、Handling Security Exceptions

ExceptionTranslationFilter可以将AccessDeniedException和AuthenticationException转换为HTTP响应。 ExceptionTranslationFilter作为安全过滤器之一被插入到FilterChainProxy中:

exceptiontranslationfilter

  1. 首先,ExceptionTranslationFilter调用FilterChain.doFilter(request, response)处理应用程序的后续逻辑

  2. 如果用户没有进行身份验证或是抛出AuthenticationException(验证异常),则启动身份验证

    • 清除SecurityContextHolder

    • 将HttpServletRequest保存在RequestCache中, 当用户成功通过身份验证时,将使用RequestCache释放原始请求

    • AuthenticationEntryPoint用于从客户机请求凭据, 例如,它可能重定向到登录页面或发送一个WWW-Authenticate报头

  3. 如果是AccessDeniedException异常,拒绝访问,然后使用AccessDeniedHandler处理拒绝访问

注意:如果应用程序没有抛出AccessDeniedException或AuthenticationException,则ExceptionTranslationFilter不会做任何事情。

ExceptionTranslationFilter的伪代码看起来像这样:

try {
    filterChain.doFilter(request, response); // 这里捕获应用程序后续任务中可能出现的AccessDeniedException和AuthenticationException异常
} catch (AccessDeniedException | AuthenticationException ex) {
    if (!authenticated || ex instanceof AuthenticationException) {
    startAuthentication(); // 如果用户没有进行身份验证或是抛出AuthenticationException(验证异常),则启动身份验证} else {
    accessDenied(); //拒绝访问}
}

上一篇:SpringSecurity------Security Expressions(六)

  相关解决方案