1. 概述
委託過濾器 (DelegatingFilterProxy) 是一種 Servlet 過濾器,它允許將控制傳遞給具有對 Spring 應用上下文訪問權限的 Filter 類。 Spring Security 嚴重依賴於這種技術。
在本教程中,我們將對其進行詳細介紹。
2. DelegatingFilterProxy</h2 align="left">
Javadoc 中指出,DelegatingFilterProxy 是一個
對標準 Servlet 過濾器的代理,將委託給 Spring 管理的實現 Filter 接口的 Bean。
在使用 Servlet 過濾器時,我們顯然需要在 Java-config 或 web.xml 中聲明它們為 filter-class,否則 Servlet 容器將忽略它們。 Spring 的 DelegatingFilterProxy 提供 web.xml 與應用程序上下文之間的橋樑。
2.1. DelegatingFilterProxy 內部工作原理
讓我們看看 DelegatingFilterProxy 如何將控制轉移到我們的 Spring Bean。
在初始化期間,DelegatingFilterProxy 會獲取 filter-name 並從 Spring Application Context 中檢索具有該名稱的 Bean。該 Bean 必須是類型為 jakarta.Servlet.Filter 的,即“正常”的 Servlet 過濾器。 傳入的請求將傳遞給該 Bean。
簡而言之,DelegatingFilterProxy 的 doFilter() 方法將委託所有調用到 Spring Bean,從而使我們能夠在過濾器 Bean 中使用所有 Spring 功能。
如果使用基於 Java 的配置,我們的過濾器註冊在 ApplicationInitializer 中將定義為:
@Override
protected Filter[] getServletFilters() {
DelegatingFilterProxy delegateFilterProxy = new DelegatingFilterProxy();
delegateFilterProxy.setTargetBeanName("applicationFilter");
return new Filter[]{delegateFilterProxy};
}如果使用XML,那麼在 web.xml 文件中:
<filter>
<filter-name>applicationFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>這意味着任何請求都可以通過 Spring 中配置為 Bean 且名稱為 applicationFilter 的過濾器進行處理。
2.2. 使用 DelegatingFilterProxy 的必要性
DelegatingFilterProxy 是 Spring Web 模塊中的一個類。它提供了一種機制,允許 HTTP 調用在到達實際目的地之前通過過濾器進行過濾。藉助 DelegatingFilterProxy,可以實現對實現 jakarta.Servlet.Filter 接口的類的注入,從而將其納入過濾器鏈。
例如,Spring Security 利用 DelegatingFilterProxy,以便可以利用 Spring 的依賴注入功能和生命週期接口,為安全過濾器提供支持。
DelegatingFilterProxy 還可以通過根據請求 URI 路徑,調用特定的或多個過濾器,在 Spring 的應用程序上下文中或 web.xml 中提供配置。
3. 創建自定義過濾器
如上所述,<em>DelegatingFilterProxy</em> 自身就是一個 servlet 過濾器,它會將請求委託給一個 Spring 管理的 bean,該 bean 實現 <em>Filter</em> 接口。
在接下來的幾個部分中,我們將創建一個自定義過濾器並使用 Java 和基於 XML 的配置進行配置。
3.1. 過濾器類
我們將創建一個簡單的過濾器,在請求進一步處理之前記錄請求信息。
首先,讓我們創建一個自定義過濾器類:
@Component("loggingFilter")
public class CustomFilter implements Filter {
private static Logger LOGGER = LoggerFactory.getLogger(CustomFilter.class);
@Override
public void init(FilterConfig config) throws ServletException {
// initialize something
}
@Override
public void doFilter(
ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
LOGGER.info("Request Info : " + req);
chain.doFilter(request, response);
}
@Override
public void destroy() {
// cleanup code, if necessary
}
}
CustomFilter 實現 jakarta.Servlet.Filter。該類具有 @Component 註解,以便在應用程序上下文中將其註冊為 Spring Bean。 這樣,DelegatingFilterProxy 類在初始化過濾器鏈時可以找到我們的過濾器類。
請注意,Spring Bean 的名稱必須與 filter-name 中提供的自定義過濾器註冊期間的值相同,因為DelegatingFilterProxy 類將在應用程序上下文中查找具有完全相同名稱的過濾器 Bean。
如果找不到具有此名稱的 Bean,則在應用程序啓動時會引發異常。
3.2. 通過 Java 配置配置過濾器
要使用 Java 配置註冊自定義過濾器,我們需要覆蓋 <em>getServletFilters()</em> 方法,該方法位於 <em>AbstractAnnotationConfigDispatcherServletInitializer</em> 中:
public class ApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
// some other methods here
@Override
protected Filter[] getServletFilters() {
DelegatingFilterProxy delegateFilterProxy = new DelegatingFilterProxy();
delegateFilterProxy.setTargetBeanName("loggingFilter");
return new Filter[]{delegateFilterProxy};
}
}3.3. 通過<em>web.xml</em>配置過濾器
以下是過濾器配置在<em>web.xml</em>中的示例:
<filter>
<filter-name>loggingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>loggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>filter-class 參數的類型為 DelegatingFilterProxy,而不是我們創建的過濾器類。如果運行這段代碼並訪問任何 URL,則 doFilter() 方法將在 CustomFilter 中執行,並在日誌文件中顯示請求信息詳情。
4. 結論
本文介紹了 DelegatingFilterProxy 的工作原理及其使用方法。
Spring Security 廣泛使用 DelegatingFilterProxy 來保護 Web API 調用和資源免受未授權訪問。