架构

我们以Spring Security中Servlet实现方式来介绍Spring Security整体架构,不会具体到具体的认证、授权来介绍Spring Security架构。如果让我们自己来写一个安全框架,我们需要将我们的框架置于项目中的哪个位置?很显然是在所有的请求到达Controller之前,在访问具体的某个Controller之前,对请求进行认证、授权、安全验证。在JakartaEE(JavaEE的新版)规范中,Filter和Servlet都符合这个前置要求。在Spring MVC中基本上只包含一个DispatcherServelt主要用于请求分发,缺乏安全相关的支持和合适的扩展机制。我们看Spring Security官方文档中的图来理解:

客户端向应用程序发送一个请求,容器创建一个 FilterChain,其中包含 Filter 实例和 Servlet,应该根据请求URI的路径来处理 HttpServletRequest。在Spring MVC应用程序中,Servlet是 DispatcherServlet 的一个实例。一个 Servlet 最多可以处理一个 HttpServletRequestHttpServletResponse。然而,可以使用多个 Filter 来完成如下工作。本质上,Spring Security的实现原理很简单,就是提供了一个用于安全验证的Filter链

DelegatingFilterProxy

Spring 提供了一个名为 DelegatingFilterProxyFilter 实现,它在Spring Security中起到了一个重要的桥梁作用,连接了Servlet容器和Spring容器。Servlet容器不了解Spring定义的Beans,而Spring Security的大部分组件及其依赖都是注册到Spring容器中的Bean。DelegatingFilterProxy核心代码的主要工作就是从WebApplicationContext获取指定名称的Filter Bean,然后委托给这个Bean的doFilter方法。

DelegatingFilterProxyApplicationContext 查找 Bean Filter0,然后调用 Bean Filter0。下面是Spring Security提供的一段伪代码,快要帮助我们理解:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
	Filter delegate = getFilterBean(someBeanName); // 1
	delegate.doFilter(request, response); // 2
}
  1. 延迟地获取被注册为Spring Bean的 Filter。 对于 DelegatingFilterProxy中的例子,delegateBean Filter0 的一个实例。
  2. 将工作委托给 Spring Bean。

FilterChainProxy

被委托的类型就是FilterChainProxy,FilterChainProxy 是 Spring Security 提供的一个特殊的 Filter,允许通过 SecurityFilterChain 委托给许多 Filter 实例。由于 FilterChainProxy 是一个Bean,它通常被包裹在 DelegatingFilterProxy 中。FilterChainProxy主要作用就是查找匹配当前Http请求规则的SecurityFilterChain,然后将工作委派给SecurityFilterChain的所有Filter。

SecurityFilterChain

SecurityFilterChainFilterChainProxy 用来确定当前请求应该调用哪些 Spring Security Filter 实例。

SecurityFilterChain 中的 Security Filter 通常是Bean,但它们是用 FilterChainProxy 而不是 DelegatingFilterProxy注册的。与直接向Servlet容器或 DelegatingFilterProxy 注册相比,FilterChainProxy 有很多优势。首先,它为 Spring Security 的所有 Servlet 支持提供了一个起点。由于这个原因,如果你试图对 Spring Security 的 Servlet 支持进行故障诊断,在 FilterChainProxy 中添加一个调试点是一个很好的开始。

其次,由于 FilterChainProxy 是 Spring Security 使用的核心,它可以执行一些不被视为可有可无的任务。 例如,它清除了 SecurityContext 以避免内存泄漏。它还应用Spring Security的 HttpFirewall来保护应用程序免受某些类型的攻击。

此外,它在确定何时应该调用 SecurityFilterChain 方面提供了更大的灵活性。在Servlet容器中,Filter 实例仅基于URL被调用。 然而,FilterChainProxy 可以通过使用 RequestMatcher 接口,根据 HttpServletRequest 中的任何内容确定调用。

Multiple SecurityFilterChain图中, FilterChainProxy 决定应该使用哪个 SecurityFilterChain。只有第一个匹配的 SecurityFilterChain 被调用。如果请求的URL是 /api/messages/,它首先与 /api/**SecurityFilterChain0 模式匹配,所以只有 SecurityFilterChain0 被调用,尽管它也与 SecurityFilterChainn 匹配。如果请求的URL是 /messages/,它与 /api/**SecurityFilterChain0 模式不匹配,所以 FilterChainProxy 继续尝试每个 SecurityFilterChain。假设没有其他 SecurityFilterChain 实例相匹配,则调用 SecurityFilterChainn

请注意,SecurityFilterChain0 只配置了三个 security Filter 实例。然而,SecurityFilterChainn 却配置了四个 security Filter 实例。值得注意的是,每个 SecurityFilterChain 都可以是唯一的,并且可以单独配置。事实上,如果应用程序希望 Spring Security 忽略某些请求,那么一个 SecurityFilterChain 可能会有零个 security Filter 实例。

Security Filter

Security Filter 是通过 SecurityFilterChainAPI 插入 [FilterChainProxy中的。

这些 filter 可以用于许多不同的目的,如 认证授权漏洞保护 等等。filter 是按照特定的顺序执行的,以保证它们在正确的时间被调用,例如,执行认证的 Filter 应该在执行授权的 Filter 之前被调用。一般来说,没有必要知道 Spring Security 的 Filter 的顺序。但是,有些时候知道顺序是有好处的,如果你想知道它们,可以查看 FilterOrderRegistration 代码。

源码分析



通过DefaultSecurityFilterChain可以看到,默认情况下会引入16个Filter。比如:UsernamePasswordAuthenticationFilter支持Form表单形式的身份验证模块。

posted @ 2024-04-19 16:58  无涯子wyz  阅读(4)  评论(0编辑  收藏  举报