# 建筑
本节讨论 Spring 基于 Servlet 的应用程序中的 Spring 安全性的高级体系结构。我们在参考的认证、授权、保护免受剥削部分中建立了这种高层次的理解。
# 《Filter
s》评介
Spring 安全性的 Servlet 支持是基于 Servlet Filter
s 的,因此通常首先查看Filter
s 的作用是有帮助的。下图显示了单个 HTTP 请求的处理程序的典型分层。
图 1。滤清链
客户机向应用程序发送一个请求,容器创建一个FilterChain
,其中包含Filter
s 和Servlet
,它们应该基于请求 URI 的路径来处理HttpServletRequest
。在 Spring MVC 应用程序中,Servlet
是[DispatcherServlet
](https://DOCS. Spring.io/ Spring-framework/DOCS/5.3.16/reference/html/web.html#mvc- Servlet)的一个实例。最多一个Servlet
可以处理单个HttpServletRequest
和HttpServletResponse
。但是,可以使用多个Filter
来:
阻止调用下游
Filter
s 或Servlet
。在这种情况下,Filter
通常会写HttpServletResponse
。修改由下游
Filter
s 和Servlet
使用的HttpServletRequest
或HttpServletResponse
Filter
的幂来自传递到它的FilterChain
。
例 1。FilterChain
用法示例
爪哇
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
}
Kotlin
fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
// 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
只会影响下游Filter
s 和Servlet
,因此每次调用Filter
的顺序是极其重要的。
# 委托过滤代理
Spring 提供了名为[Filter
](https://DOCS. Spring.io/ Spring-framework/DOCS/5.3.16/javadoc-api/org/springframework/web/filter/delegatingfilterproxy.html)的Filter
实现,该实现允许在 Servlet 容器的生命周期和 Spring 的ApplicationContext
之间架桥。 Servlet 容器允许使用自己的标准注册Filter
s,但它不知道 Spring 定义的 bean。DelegatingFilterProxy
可以通过标准 Servlet 容器机制注册,但将所有工作委托给实现Filter
的 Spring Bean。
下面是一张DelegatingFilterProxy
如何与[Filter
s 和FilterChain
](# Servlet-filters-review)相匹配的图片。
图 2。委托过滤代理
DelegatingFilterProxy
从ApplicationContext
中查找Bean Filter0,然后调用Bean Filter0。下面可以看到DelegatingFilterProxy
的伪代码。
例 2。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);
}
Kotlin
fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
// Lazily get Filter that was registered as a Spring Bean
// For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
val delegate: Filter = getFilterBean(someBeanName)
// delegate work to the Spring Bean
delegate.doFilter(request, response)
}
DelegatingFilterProxy
的另一个好处是,它允许延迟查找Filter
Bean 实例。这一点很重要,因为容器在启动之前需要注册Filter
实例。然而, Spring 通常使用ContextLoaderListener
来加载 Spring bean,这在Filter
实例需要注册之后才能完成。
# FilterchainProxy
Spring Security 的 Servlet 支持包含在FilterChainProxy
中。FilterChainProxy
是 Spring Security 提供的一种特殊的Filter
,它允许通过[证券过滤链
](# Servlet-SecurityFilterchain)将许多Filter
实例委托给多个实例。由于FilterChainProxy
是 Bean,因此它通常被包装在委托过滤代理中。
图 3。FilterchainProxy
# SecurityFilterChain
[SecurityFilterChain
](https://DOCS. Spring.io/ Spring-security/site/DOCS/5.6.2/api/org/springframework/security/web/securityfilterchain.html)被FilterchainProxy 用于确定应该为此请求调用哪个 Spring securityFilter
s。
图 4。证券过滤链
安全过滤器中的SecurityFilterChain
通常是 bean,但它们是用FilterChainProxy
而不是委托过滤代理注册的。FilterChainProxy
提供了直接向 Servlet 容器或委托过滤代理注册的许多优点。首先,它为 Spring Security 的 Servlet 支持提供了一个起点。因此,如果你试图对 Spring Security 的 Servlet 支持进行故障排除,那么在FilterChainProxy
中添加一个调试点是一个很好的起点。
其次,由于FilterChainProxy
是 Spring 安全性使用的核心,因此它可以执行不被视为可选的任务。例如,它清除SecurityContext
以避免内存泄漏。它还应用 Spring Security 的[HttpFirewall
](exploits/firewall.html# Servlet-HttpFirewall)来保护应用程序免受某些类型的攻击。
此外,它在确定何时应该调用SecurityFilterChain
时提供了更大的灵活性。在 Servlet 容器中,Filter
s 仅基于 URL 被调用。但是,FilterChainProxy
可以通过利用RequestMatcher
接口,基于HttpServletRequest
中的任何内容来确定调用。
事实上,FilterChainProxy
可以用来确定应该使用哪些SecurityFilterChain
。这允许为应用程序的不同切片提供完全独立的配置。
图 5。多重证券过滤链
在多重证券过滤链图中,FilterChainProxy
决定应该使用哪个SecurityFilterChain
。只调用第一个匹配的SecurityFilterChain
。如果请求/api/messages/
的 URL,它将首先匹配SecurityFilterChain<sub>0</sub>
的/api/**
的模式,因此只有SecurityFilterChain<sub>0</sub>
将被调用,即使它也匹配SecurityFilterChain<sub>n</sub>
。如果请求一个/messages/
的 URL,它将不匹配SecurityFilterChain<sub>0</sub>
的/api/**
的模式,因此FilterChainProxy
将继续尝试每个SecurityFilterChain
。假设没有其他的,SecurityFilterChain
实例匹配SecurityFilterChain<sub>n</sub>
将被调用。
请注意,SecurityFilterChain<sub>0</sub>
只配置了三个安全Filter
实例。但是,SecurityFilterChain<sub>n</sub>
配置了四个Filter
的安全性。需要注意的是,每个SecurityFilterChain
都可以是唯一的,并且可以单独配置。实际上,如果应用程序希望 Spring 安全性忽略某些请求,则SecurityFilterChain
可能具有零安全性Filter
s。
# 安全过滤器
使用证券过滤链API 将安全过滤器插入FilterchainProxy 中。[Filter
](# Servlet-过滤器-评审)的顺序很重要。通常不需要知道 Spring 证券的Filter
s 的排序。
下面是 Spring 安全过滤器排序的综合列表:
通道处理滤波器
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
Corsfilter
Csrffilter
LogoutFilter
OAuth2AuthorizationRequestReDirectFilter
SAML2WebssoAuthenticationRequestFilter
X509 身份验证过滤器
抽象预先验证的处理过滤器
CasauthenticationFilter
OAuth2 登录验证过滤器
SAML2WebssoAuthenticationFilter
[
UsernamePasswordAuthenticationFilter
](身份验证/密码/form.html# Servlet-身份验证-usernamepasswordauthenticationfilter)openidauthenticationfilter
DefaultLoginPageGeneratingFilter
DefaultLogOutpageGeneratingFilter
ConcurrentSessionFilter
[
DigestAuthenticationFilter
](authentication/passwords/digest.html# Servlet-authentication-digest)BeareRtoKenAuthenticationFilter
[
BasicAuthenticationFilter
](authentication/passwords/basic.html# Servlet-authentication-basic)RequestCacheAwareFilter
SecurityContextholderAwareRequestFilter
JaasapiIntegrationfilter
RememerMeAuthenticationFilter
匿名身份验证过滤器
OAuth2AuthorizationCodeGrantFilter
SessionManagementFilter
[
ExceptionTranslationFilter
](# Servlet-ExceptionTranslationFilter)[
FilterSecurityInterceptor
](授权/authorization-requests.html# Servlet-authorization-filtersecurityinterceptor)切换 chuserfilter
# 处理安全异常
[ExceptionTranslationFilter
](https://DOCS. Spring.io/ Spring-security/site/DOCS/5.6.2/api/org/springframework/security/web/access/excess/exceptiontranslationfilter.html)允许将[AccessDeniedException
](https://DOCS. Spring.io/ Spring.io/ Spring-cesecurity/site/DOCS/5.6.2/api/api/org/accessframework/secframework/securance/securance/securation/acception/acc
ExceptionTranslationFilter
作为安全过滤器中的一个插入到FilterchainProxy 中。
首先,
ExceptionTranslationFilter
调用FilterChain.doFilter(request, response)
来调用应用程序的其余部分。如果用户没有经过身份验证,或者它是
AuthenticationException
,那么启动身份验证。HttpServletRequest
保存在[RequestCache
](https://DOCS. Spring.io/ Spring-security/site/DOCS/5.6.2/api/org/springframework/security/web/savedrequest/requestcache.html)中。当用户成功进行身份验证时,将使用RequestCache
重播原始请求。AuthenticationEntryPoint
用于从客户机请求凭据。例如,它可能重定向到一个登录页面,或者发送一个WWW-Authenticate
头。
否则如果是
AccessDeniedException
,则访问被拒绝。调用AccessDeniedHandler
来处理拒绝访问。
如果应用程序不抛出AccessDeniedException 或AuthenticationException ,则ExceptionTranslationFilter 不执行任何操作。 |
---|
ExceptionTranslationFilter
的伪代码如下所示:
ExceptionTranslationFilter 伪码
try {
filterChain.doFilter(request, response); (1)
} catch (AccessDeniedException | AuthenticationException ex) {
if (!authenticated || ex instanceof AuthenticationException) {
startAuthentication(); (2)
} else {
accessDenied(); (3)
}
}
1 | 你可以从[对Filter s 的回顾](# Servlet-filters-review)中回忆起,调用FilterChain.doFilter(request, response) 相当于调用应用程序的其余部分。这意味着,如果应用程序的另一部分,(即[ FilterSecurityInterceptor ](Authorization/authorization-requests.html# Servlet-authorization-filterSecurityInterceptor)或方法安全性)抛出一个AuthenticationException 或AccessDeniedException 将在此捕获并处理。 |
---|---|
2 | 如果用户没有经过身份验证,或者它是AuthenticationException ,那么启动身份验证。 |
3 | 否则,访问被拒绝 |
← 你好 Spring 安全 认证 →