SpringSecurity中文文档——Architecture

8 篇文章 1 订阅
6 篇文章 1 订阅


Spring Security 的 Serlvet支持是基于Servelt的过滤器实现的,下图展示了一个HTTP请求典型的分层处理过程。
在这里插入图片描述
当客户端发送一个请求到应用时,容器会创建一个过滤器链FilterChain,包含Filter和基于请求URI处理HttpServletRequest 的Servlet。在SpringMVC应用中,Servlet是DispatcherServlet的一个实例。一个Servlet最多只能处理一个HttpServletRequest和HttpServletResponse。
但是,可以使用多个过滤器来:

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

DelegatingFilterProxy

Spring提供了一个名叫DelegatingFilterProxy的Filter实现,来桥接Servlet容器的生命周期和Spring的上下文ApplicationContext。Servlet容器允许使用自己的标准注册过滤器,但它不知道Spring定义的bean。DelegatingFilterProxy可以通过标准的Servlet容器机制注册,将所有工作委托给实现过滤器的Springbean。
在这里插入图片描述
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中。
在这里插入图片描述

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

private List<Filter> getFilters(HttpServletRequest request) {
	for (SecurityFilterChain chain : filterChains) {
		if (chain.matches(request)) {
			return chain.getFilters();
		}
	}
	return null;
}

HttpFirewall

用于拒绝潜在危险的请求,该实现被注入FilterChainProxy,并在通过过滤器链发送任何请求之前被调用。如果响应行为也应该受到限制,它还可以提供一个响应包装器。我们看到HttpFirewall接口提供了两个抽象方法getFirewalledRequest、getFirewalledResponse分别用于校验请求和响应,默认使用StrictHttpFirewall类的实例,我们看看getFirewalledRequest方法中做了哪些事情:

  1. 先拒绝了请求URL上包含%25、%2e、%2f等特殊encode和decode编码的请求
  2. 其次再校验一个请求URL是否是正常的,不能包含类似"./", “/…/” 或 "/."这样的请求
  3. 最后通过比较URL每一位字符的ASCII码来排除有特殊字符的URL。

getFirewalledResponse默认不做任何处理,直接将请求返回前端。

SecurityFilterChain

FilterChainProxy使用SecurityFilterChain来确定应该为此请求调用哪些SpringSecurity的Filter。
在这里插入图片描述
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。

在这里插入图片描述

  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不做任何事。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值