我在 Spring MVC 应用程序的 web.xml
中看到了这一点:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
我试图弄清楚它为什么存在以及它是否真的需要。
我找到了 this explanation in the Spring docs,但它并不能帮助我理解它:
似乎表明该组件是 web.xml
中定义的 servlet 和 Spring applicationContext.xml
中定义的组件之间的“粘合剂”。
7.1 DelegatingFilterProxy 当使用servlet过滤器时,你显然需要在你的web.xml中声明它们,否则它们会被servlet容器忽略。在 Spring Security 中,过滤器类也是在应用程序上下文中定义的 Spring bean,因此能够利用 Spring 丰富的依赖注入设施和生命周期接口。 Spring 的 DelegatingFilterProxy 提供了 web.xml 和应用程序上下文之间的链接。使用 DelegatingFilterProxy 时,您会在 web.xml 文件中看到如下内容:
那么,如果我把它从我的 web.xml
中取出,会发生什么?我的 servlet 将无法与 Spring 容器通信?**
这里有某种魔法,但归根结底,一切都是确定性程序。
DelegatingFilterProxy 是一个如上所述的过滤器,其目标是“委托给实现过滤器接口的 Spring 管理的 bean”,即它在您的 Spring 应用程序中找到一个 bean(“目标 bean”或“委托”)上下文并调用它。这怎么可能?因为这个bean 实现了javax.servlet.Filter,所以它的doFilter 方法被调用了。
叫什么豆? DelegatingFilterProxy “支持“targetBeanName” [...],在 Spring 应用程序上下文中指定目标 bean 的名称。”
正如您在 web.xml 中看到的,bean 的名称是“springSecurityFilterChain”。
因此,在 Web 应用程序的上下文中,过滤器在应用程序上下文中实例化一个名为“springSecurityFilterChain”的 bean,然后通过 doFilter() 方法委托给它。
请记住,您的应用程序上下文是使用所有应用程序上下文 (XML) 文件定义的。例如:applicationContext.xml 和 applicationContext-security.xml。
所以尝试在后者中找到一个名为“springSecurityFilterChain”的bean...
...并且可能您不能(例如,如果您遵循教程或使用 Roo 配置了安全性)
神奇之处在于:有一个用于配置安全性的新元素,例如
<http auto-config="true" use-expressions="true">
正如 http://www.springframework.org/schema/security/spring-security-3.0.xsd 所允许的那样,就可以了。
当 Spring 使用 XML 文件加载应用程序上下文时,如果找到一个元素,它将尝试设置 HTTP 安全性,即过滤器堆栈和受保护的 URL,并注册名为“springSecurityFilterChain”的 FilterChainProxy。
或者,您可以以经典方式定义 bean,即:
<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
但不太推荐,因为您需要进行大量配置(您将要使用的所有过滤器。而且有十几个)
您知道 Servlet Filter 是什么以及它是如何工作的吗?它是 Servlet 规范中非常有用的部分,允许我们将类似 AOP 的概念应用于 HTTP 请求的服务。许多框架将过滤器实现用于各种事情,并且找到它们的自定义实现并不少见,因为它们非常易于编写且非常有用。在 Spring 应用程序中,您的应用程序可以做的大部分事情都在您的 Spring bean 中。但是,Filter 实例由 Servlet 容器控制。容器实例化、初始化和销毁它。不过,Servlet 规范不需要任何类型的 Spring 集成,因此您留下了一个非常有用的概念(过滤器),没有方便的方法将其与您的 Spring 应用程序和执行工作的 bean 联系起来。
输入 DelegatingFilterProxy。您编写了一个过滤器实现并使其成为一个 Spring bean,但不是将您自己的过滤器类添加到 web.xml,而是使用 DelegatingFilterProxy,并在 Spring 上下文中为其提供过滤器的 bean 名称。 (如果您没有明确提供名称,它使用“过滤器名称”。)然后在运行时,DelegatingFilterProxy 处理查找实际实现的复杂性 - 您在 Spring 中编写和配置的实现 - 并将请求路由到它.因此,在运行时,就好像您已经在 web.xml 中列出了您的过滤器,但是您可以像其他任何 Spring bean 一样连接它,从而获得好处。
如果您将过滤器映射从您的 web.xml 中取出,一切都会继续工作,但您的任何 URL 都不会受到保护。 (假设名称“springSecurityFilterChain”准确地描述了它的作用。)这是因为此映射过滤每个传入的请求并将其交给在 Spring 上下文中定义的安全过滤器。
什么是 Servlet 过滤器?
Servlet filters 通常是一个 Java WebApp 概念。无论您是否在应用程序中使用 Spring 框架,您都可以在任何 web 应用程序中使用 servlet 过滤器。
这些过滤器可以在请求到达目标 servlet 之前拦截它们。您可以在 servlet 过滤器中实现通用功能,例如授权。实施后,您可以在 web.xml 中配置过滤器以应用于特定的 servlet、特定的请求 url 模式或所有 url 模式。
servlet 过滤器在哪里使用?
现代网络应用程序可以有几十个这样的过滤器。诸如授权、缓存、ORM 会话管理和依赖注入之类的东西通常是在 servlet 过滤器的帮助下实现的。所有这些过滤器都需要在 web.xml
中注册。
实例化 Servlet 过滤器 - 没有 Spring 框架
您的 servlet 容器创建在 web.xml
中声明的过滤器实例并在适当的时间(即,在为 servlet 请求提供服务时)调用它们。现在,如果您像大多数依赖注入 (DI) 粉丝一样,您可能会说创建实例是我的 DI 框架 (Spring) 做得更好的地方。我不能用 Spring 创建我的 servlet 过滤器,以便它们适合所有 DI 优点吗?
DelegatingFilterProxy,以便 Spring 创建您的过滤器实例
这是 DelegatingFilterProxy
介入的地方。DelegatingFilterProxy
是 Spring Framework 提供的 javax.servlet.Filter
接口的实现。在 web.xml 中配置 DelegatingFilterProxy
后,您可以在 spring 配置中声明执行过滤的实际 beans。这样,Spring 创建了执行实际过滤的 bean 实例,您可以使用 DI 来配置这些 bean。
请注意,您只需要在 web.xml
中声明一个 DelegatingFilterProxy
,但您可以在应用程序上下文中将多个过滤 bean
链接在一起。
问题是,servlet 过滤器是由 servlet 容器管理的,而不是由 spring 管理的。您可能需要在过滤器中注入一些弹簧组件。
所以,如果你需要类似的东西:
public class FooFilter {
@Inject
private FooService service;
public void doFilter(....) { .. }
}
那么您需要委托过滤器代理。
你对“胶水”的东西是对的。如 FilterChainProxy 的 JavaDocs 中所写:
通过在应用程序 web.xml 文件中添加标准 Spring DelegatingFilterProxy 声明,FilterChainProxy 链接到 servlet 容器过滤器链。
请参阅博客 Behind the Spring Security Namespace 的 FIlterChainProxy 部分以获得出色的解释。
我对 web.xml 中的“springSecurityFilterChain”感到困惑,并在 springframework 安全文档中找到了这个答案:
这是链接http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html
已经很长时间了,但我有同样的问题,我发现了这个:https://www.javacodegeeks.com/2013/11/spring-security-behind-the-scenes.html
我试图通过删除有问题的过滤器并添加它来运行我的 spring 安全项目。我发现如果我们添加过滤器,那么只有调用才会重定向到 spring-security 配置中定义的所需登录页面。
因此,同意@Ryan 的回答。