解锁 Spring Security:深入底层原理
Spring Security 是一个强大且灵活的安全框架,其核心功能包括身份认证、授权和防御常见攻击。要深入了解其底层原理,需要理解以下关键概念和组件。而Spring Security的底层原理是传统的 Servlet过滤器 ,欲了解更多详细信息,您可以访问 Architecture :: Spring Security。
1. A Review of Filters
下图展示了处理一个Http请求时,过滤器和Servlet的工作流程
客户端向应用程序发送请求,容器根据请求 URI 的路径创建一个FilterChain
,其中包含应处理HttpServletRequest
的Filter
实例和Servlet
。在 Spring MVC 应用程序中,Servlet
是DispatcherServlet
的实例。一个Servlet
最多可以处理一个HttpServletRequest
和HttpServletResponse
。然而,多个Filter
可用于:
- 防止调用下游
Filter
实例或Servlet
。在这种情况下,Filter
通常会写入HttpServletResponse
。 - 修改下游
Filter
实例和Servlet
使用的HttpServletRequest
或HttpServletResponse
。
FilterChain
的使用示例:
1 | public void doFilter(ServletRequest request, |
由于Filter
仅影响下游Filter
实例和Servlet
,因此调用每个Filter
顺序非常重要。
2. DelegatingFilterProxy
Spring 提供了一个名为DelegatingFilterProxy
的Filter
实现,它允许在 Servlet 容器的生命周期和 Spring 的ApplicationContext
之间进行桥接。 Servlet容器允许使用自己的标准注册Filter
实例,但它不知道Spring定义的Bean。可以通过标准 Servlet 容器机制注册DelegatingFilterProxy
,但将所有工作委托给实现Filter
Spring Bean。
DelegatingFilterProxy
从ApplicationContext
中查找 Bean Filter 0 ,然后调用 Bean Filter 0。
1 | public void doFilter(ServletRequest request, |
DelegatingFilterProxy
的另一个好处是它允许延迟查找Filter
bean 实例。这很重要,因为容器需要在容器启动之前注册Filter
实例。然而,Spring 通常使用ContextLoaderListener
来加载 Spring Bean,直到需要注册Filter
实例之后才会完成此操作。
3. FilterChainProxy
Spring Security 的 Servlet 支持包含在FilterChainProxy
中。 FilterChainProxy
是 Spring Security 提供的一个特殊Filter
,它允许通过 SecurityFilterChain
委托给许多Filter
实例。由于FilterChainProxy
是一个 Bean,因此它通常包装在 DelegatingFilterProxy 中。
4. SecurityFilterChain
FilterChainProxy使用SecurityFilterChain
来确定应为当前请求调用哪些 Spring Security Filter
实例。
SecurityFilterChain
中的安全过滤器通常是 Bean,但它们是使用FilterChainProxy
而不是DelegatingFilterProxy注册的。 FilterChainProxy
提供了直接向 Servlet 容器或DelegatingFilterProxy注册的许多优点。首先,它为 Spring Security 的所有 Servlet 支持提供了一个起点。因此,如果尝试对 Spring Security 的 Servlet 支持进行故障排除,那么在FilterChainProxy
中添加调试点是一个很好的起点。
由于FilterChainProxy
是 Spring Security 使用的核心,因此它可以执行不被视为可选的任务。例如,它清除SecurityContext
以避免内存泄漏。它还应用 Spring Security 的HttpFirewall
来保护应用程序免受某些类型的攻击。
它在确定何时应调用SecurityFilterChain
方面提供了更大的灵活性。在 Servlet 容器中,仅根据 URL 调用Filter
实例。但是, FilterChainProxy
可以使用RequestMatcher
接口根据HttpServletRequest
中的任何内容确定调用。
在上图中, FilterChainProxy
决定应使用哪个SecurityFilterChain
。仅调用第一个匹配的SecurityFilterChain
。如果请求/api/messages/
的 URL,它首先匹配/api/**
的SecurityFilterChain 0
模式,因此仅调用SecurityFilterChain 0
,即使它也匹配SecurityFilterChain n
。如果请求/messages/
的 URL,则它与/api/**
的SecurityFilterChain 0
模式不匹配,因此FilterChainProxy
继续尝试每个SecurityFilterChain
。假设没有其他SecurityFilterChain
实例匹配,则调用SecurityFilterChain n
。SecurityFilterChain 0
仅配置了三个安全Filter
实例。然而, SecurityFilterChain n
配置了四个安全Filter
实例。需要注意的是,每个SecurityFilterChain
都可以是唯一的,并且可以单独配置。事实上,如果应用程序希望 Spring Security 忽略某些请求, SecurityFilterChain
安全Filter
实例可能为零。
5. Security Filters
安全过滤器通过SecurityFilterChain API 插入到FilterChainProxy中。这些过滤器可用于多种不同的目的,例如身份验证、授权、漏洞保护等。过滤器按照特定的顺序执行,以保证它们在正确的时间被调用,例如,执行身份验证的Filter
应该在执行授权的Filter
之前被调用。通常不需要知道 Spring Security 的Filter
的顺序。但是,有时了解顺序是有好处的,如果您想了解它们,可以检查FilterOrderRegistration
代码。
1 |
|