本文共 4055 字,大约阅读时间需要 13 分钟。
Filter
Spring Security的Servlet支持是基于Servlet的Filter
,所以首先看看过滤器的作用是很有帮助的。下图显示了单个HTTP请求的处理程序的典型分层。
客户端向应用程序发送请求,容器创建一个包含Filter和Servlet的FilterChain
,这些filter和Servlet基于请求URI的路径来处理HttpServletRequest
。
DelegatingFilterProxy
Spring提供了一个名为DelegatingFilterProxy
的过滤器实现,它允许在Servlet容器的生命周期和Spring的ApplicationContext
之间进行桥接。Servlet容器允许使用它自己的标准注册Filter,但是它不知道Spring定义的bean。DelegatingFilterProxy
可以通过标准的Servlet容器机制注册,但是可以将所有的工作委托给实现Filter的Spring Bean。
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);}
FilterChainProxy
Spring Security的Servlet支持包含在FilterChainProxy
中。FilterChainProxy
是Spring Security提供的一个特殊的Filter
,它允许通过SecurityFilterChain
委托给许多Filter
实例。由于FilterChainProxy
是一个Bean,它通常被封装在DelegatingFilterProxy
中。
SecurityFilterChain
SecurityFilterChain
被FilterChainProxy
用来确定应该为这个请求调用哪个Spring Security Filter
。
SecurityFilterChain
中的Security Filter
通常是bean,但是它们注册在FilterChainProxy
而不是DelegatingFilterProxy
上。FilterChainProxy
为直接注册Servlet容器或DelegatingFilterProxy
提供了许多优势。
首先,它为所有Spring Security的Servlet支持提供了一个起点。因此,如果您试图排除Spring Security的Servlet支持,那么在FilterChainProxy
中添加一个调试点是一个很好的开始。
第二,由于FilterChainProxy
是Spring安全使用的中心,它可以执行一些不是可选的任务。例如,它清除SecurityContext
以避免内存泄漏。它还应用Spring Security的HttpFirewall
来保护应用程序免受某些类型的攻击。
此外,它在确定何时应该调用SecurityFilterChain
方面提供了更多的灵活性。在Servlet容器中,只根据URL调用Filter
。然而,FilterChainProxy
可以通过利用RequestMatcher
接口来根据HttpServletRequest
中的任何内容来确定调用。
事实上,FilterChainProxy
可以用来确定应该使用哪个SecurityFilterChain
。这允许在应用程序中为不同的片提供完全独立的配置。
在上图中,FilterChainProxy
决定应该使用哪个SecurityFilterChain
。
-
只有第一个匹配的
SecurityFilterChain
将被调用。 -
如果请求一个
/api/messages/
的URL,- 首先匹配
SecurityFilterChain_0
的/api/**
模式,所以只有SecurityFilterChain0
将被调用,即使它也匹配SecurityFilterChain_n
。
- 首先匹配
-
如果请求的URL是
/messages/
,- 不匹配
SecurityFilterChain_0
的/api/**
模式, FilterChainProxy
将继续尝试每个SecurityFilterChain
。- 假设没有其他SecurityFilterChain实例匹配
SecurityFilterChain_n
将被调用。
- 不匹配
Security Filters
Security Filter通过SecurityFilterChain
API插入到FilterChainProxy
中。Filter
的顺序很重要。通常不需要知道Spring Security Filter
的顺序。然而,有时知道顺序是有益的
下面是Spring Security Filter排序的综合列表:
- ChannelProcessingFilter
- ConcurrentSessionFilter
- WebAsyncManagerIntegrationFilter
- SecurityContextPersistenceFilter
- HeaderWriterFilter
- CorsFilter
- CsrfFilter
- LogoutFilter
- OAuth2AuthorizationRequestRedirectFilter
- Saml2WebSsoAuthenticationRequestFilter
- X509AuthenticationFilter
- AbstractPreAuthenticatedProcessingFilter
- CasAuthenticationFilter
- OAuth2LoginAuthenticationFilter
- Saml2WebSsoAuthenticationFilter
- ConcurrentSessionFilter
- OpenIDAuthenticationFilter
- DefaultLoginPageGeneratingFilter
- DefaultLogoutPageGeneratingFilter
- BearerTokenAuthenticationFilter
- RequestCacheAwareFilter
- SecurityContextHolderAwareRequestFilter
- JaasApiIntegrationFilter
- RememberMeAuthenticationFilter
- AnonymousAuthenticationFilter
- OAuth2AuthorizationCodeGrantFilter
- SessionManagementFilter
- SwitchUserFilter
处理Security异常
ExceptionTranslationFilter
允许将AccessDeniedException
和AuthenticationException
转换为HTTP响应。
ExceptionTranslationFilter
作为一个Filter
被插入到FilterChainProxy
中。
① 首先,ExceptionTranslationFilter
调用FilterChain.doFilter(request, response)
来执行应用程序的其余部分。
② 如果用户未经过身份验证或是AuthenticationException
,则开始认证。
- 清除
SecurityContextHolder
HttpServletRequest
保存在RequestCache
中。当用户认证成功时,将使用RequestCache
重新执行原始请求AuthenticationEntryPoint
用于从客户端请求凭据。例如,它可能重定向到一个登录页面或发送一个WWW-Authenticate
头。
③否则,如果是AccessDeniedException
,则拒绝访问。调用AccessDeniedHandler
来处理拒绝访问。
ℹ️如果应用程序没有抛出AccessDeniedException或AuthenticationException,那么ExceptionTranslationFilter不会做任何事情。
ExceptionTranslationFilter
的伪代码如下所示:
try { filterChain.doFilter(request, response); } catch (AccessDeniedException | AuthenticationException e) { if (!authenticated || e instanceof AuthenticationException) { startAuthentication(); } else { accessDenied(); }}
转载地址:https://console.blog.csdn.net/article/details/116456486 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!