|
此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security 6.4.3! |
架构
本节讨论 Spring Security 在基于 Servlet 的应用程序中的高级体系结构。 我们在参考的 Authentication, Authorization, Protection Against Exploits 部分建立了这种高层次的理解。
回顾Filters
Spring Security 的 Servlet 支持基于 ServletFilters 中,因此查看Filters 通常排在第一位。
下图显示了单个 HTTP 请求的处理程序的典型分层。
客户端向应用程序发送请求,容器创建一个FilterChain其中包含Filters 和Servlet它应该处理HttpServletRequest基于请求 URI 的路径。
在 Spring MVC 应用程序中,Servlet是DispatcherServlet.
最多一个Servlet可以处理单个HttpServletRequest和HttpServletResponse.
但是,不止一个Filter可用于:
-
防止下游
Filters 或Servlet免于被调用。 在本例中,Filter通常会写入HttpServletResponse. -
修改
HttpServletRequest或HttpServletResponse由下游使用Filters 和Servlet
的强大功能Filter来自FilterChain这被传递到它里面。
FilterChain使用示例-
Java
-
Kotlin
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
}
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仅影响下游Filters 和Servlet,则每个Filter非常重要。
委托过滤器代理
Spring 提供了一个Filter名为DelegatingFilterProxy这允许在 Servlet 容器的生命周期和 Spring 的生命周期之间架起桥梁ApplicationContext.
Servlet 容器允许注册Filter使用自己的标准,但它不知道 Spring 定义的 Bean。DelegatingFilterProxy可以通过标准的 Servlet 容器机制进行注册,但将所有工作委托给实现Filter.
这是一张如何作的图片DelegatingFilterProxy适合Filters 和FilterChain.
DelegatingFilterProxy查找Bean 过滤器0从ApplicationContext然后调用Bean 过滤器0.
的伪代码DelegatingFilterProxy可以在下面看到。
DelegatingFilterProxy伪代码-
Java
-
Kotlin
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);
}
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是它允许延迟查找Filterbean 实例。
这很重要,因为容器需要注册Filter实例。
但是, Spring 通常使用ContextLoaderListener加载 Spring Bean,这只有在Filter需要注册实例。
FilterChainProxy
Spring Security 的 Servlet 支持包含在FilterChainProxy.FilterChainProxy是一种特殊的Filter由 Spring Security 提供,允许委托给多个Filter实例SecurityFilterChain.
因为FilterChainProxy是一个 Bean,它通常包装在 DelegatingFilterProxy 中。
SecurityFilterChain 安全过滤器链
SecurityFilterChain被 FilterChainProxy 用于确定哪个 Spring SecurityFilters 的请求。
安全过滤器SecurityFilterChain通常是 Bean,但它们是使用FilterChainProxy而不是 DelegatingFilterProxy。FilterChainProxy为直接向 Servlet 容器或 DelegatingFilterProxy 注册提供了许多优势。
首先,它为 Spring Security 的所有 Servlet 支持提供了一个起点。
因此,如果您尝试对 Spring Security 的 Servlet 支持进行故障排除,请在FilterChainProxy是一个很好的起点。
其次,由于FilterChainProxy是 Spring Security 使用的核心,它可以执行不被视为可选的任务。
例如,它会清除SecurityContext以避免内存泄漏。
它还应用 Spring Security 的HttpFirewall保护应用程序免受某些类型的攻击。
此外,它还在确定何时SecurityFilterChain应该调用。
在 Servlet 容器中,Filter仅根据 URL 调用。
然而FilterChainProxy可以根据HttpServletRequest通过利用RequestMatcher接口。
事实上FilterChainProxy可用于确定哪个SecurityFilterChain应该使用。
这允许为应用程序的不同切片提供完全独立的配置。
在多个 SecurityFilterChain 图FilterChainProxy决定哪个SecurityFilterChain应该使用。
只有第一个SecurityFilterChain的匹配项。
如果 URL 为/api/messages/请求时,它将首先匹配SecurityFilterChain0的模式/api/**,所以只有SecurityFilterChain0将被调用,即使它也匹配SecurityFilterChainn.
如果 URL 为/messages/时,它不会匹配SecurityFilterChain0的模式/api/**所以FilterChainProxy将继续尝试每个SecurityFilterChain.
假设没有其他人,SecurityFilterChain实例匹配SecurityFilterChainn将被调用。
请注意,SecurityFilterChain0只有三个安全Filters 实例。
然而SecurityFilterChainn有四项安全保障Filter已配置。
需要注意的是,每个SecurityFilterChain可以是唯一的,并且可以单独配置。
实际上,SecurityFilterChain可能具有零安全性Filter如果应用程序希望 Spring Security 忽略某些请求,则 s
安全过滤器
安全筛选器使用 SecurityFilterChain API 插入到 FilterChainProxy 中。
这顺序Filter很重要。
通常不需要知道 Spring Security 的Filters.
但是,有时了解顺序是有益的
以下是 Spring Security 过滤器订购的完整列表:
-
ChannelProcessingFilter
-
WebAsyncManagerIntegrationFilter
-
SecurityContextPersistenceFilter
-
HeaderWriterFilter
-
CorsFilter 过滤器
-
Csrf过滤器
-
LogoutFilter
-
OAuth2AuthorizationRequestRedirectFilter
-
Saml2WebSsoAuthenticationRequestFilter
-
X509AuthenticationFilter
-
AbstractPreAuthenticatedProcessingFilter
-
CasAuthenticationFilter 的
-
OAuth2LoginAuthenticationFilter
-
Saml2WebSsoAuthenticationFilter
-
OpenIDAuthenticationFilter
-
DefaultLoginPageGeneratingFilter
-
DefaultLogoutPageGeneratingFilter
-
ConcurrentSessionFilter
-
BearerTokenAuthenticationFilter
-
RequestCacheAwareFilter
-
SecurityContextHolderAwareRequestFilter
-
JaasApiIntegrationFilter
-
RememberMeAuthenticationFilter
-
匿名身份验证过滤器
-
OAuth2AuthorizationCodeGrantFilter
-
会话管理过滤器
-
SwitchUserFilter
处理安全异常
这ExceptionTranslationFilter允许翻译AccessDeniedException和AuthenticationException转换为 HTTP 响应。
ExceptionTranslationFilter作为安全筛选器之一插入到 FilterChainProxy 中。
-
首先,ExceptionTranslationFilter调用FilterChain.doFilter(request, response)以调用应用程序的其余部分。 -
如果用户未经过身份验证或用户是AuthenticationException,然后单击 Start Authentication (开始身份验证)。-
这
HttpServletRequest保存在RequestCache. 当用户成功进行身份验证时,RequestCache用于重放原始请求。 -
这
AuthenticationEntryPoint用于向客户端请求凭据。 例如,它可能会重定向到登录页面或发送WWW-Authenticate页眉。
-
否则,如果它是AccessDeniedException,然后单击 Access Denied。 这AccessDeniedHandler用于处理 Access Denied。
|
如果应用程序没有抛出 |
的伪代码ExceptionTranslationFilter看起来像这样:
try {
filterChain.doFilter(request, response); (1)
} catch (AccessDeniedException | AuthenticationException ex) {
if (!authenticated || ex instanceof AuthenticationException) {
startAuthentication(); (2)
} else {
accessDenied(); (3)
}
}
| 1 | 您将回忆起回顾Filters那个祈求者FilterChain.doFilter(request, response)等效于调用应用程序的其余部分。
这意味着,如果应用程序的另一部分(即FilterSecurityInterceptor或方法安全性)会抛出一个AuthenticationException或AccessDeniedException它将在这里被捕获和处理。 |
| 2 | 如果用户未经过身份验证或用户是AuthenticationException,然后单击 Start Authentication (开始身份验证)。 |
| 3 | 否则,Access Denied (访问被拒绝) |