SpringSecurity--DelegatingFilterProxy工作流程

什么是 DelegatingFilterProxy

DelegatingFilterProxy 是 Spring 提供的一个特殊的过滤器,它起到了桥梁的作用,可以让你在 Spring 容器中管理 Servlet 容器中的过滤器。

为什么需要 DelegatingFilterProxy

通常情况下,Servlet 容器中的过滤器是由 Servlet 容器直接管理的,但这样有一些局限性,比如你不能方便地使用 Spring 的依赖注入来管理过滤器的依赖。通过使用 DelegatingFilterProxy,你可以把过滤器放到 Spring 容器中管理,享受 Spring 提供的各种功能。

怎么理解 DelegatingFilterProxy 的工作流程?

  1. 配置过滤器 :你在 web.xml 文件中配置了一个过滤器,但这个过滤器实际上是 DelegatingFilterProxy
  2. 委托处理DelegatingFilterProxy 会将请求委托给 Spring 容器中定义的某个具体的过滤器(这个过滤器是一个 Spring Bean)。
  3. Spring 管理:这个具体的过滤器可以使用 Spring 的各种功能,比如依赖注入、事务管理等等。

示例:使用 DelegatingFilterProxy 配置 Spring Security

假设我们需要在一个 Spring 项目中使用 Spring Security 来管理权限验证。我们将通过 DelegatingFilterProxy 将 Spring Security 的过滤器配置到 Spring 容器中。

1. 配置 web.xml

web.xml 文件中,我们配置一个 DelegatingFilterProxy,并指定 Spring Security 的过滤器 Bean 名称。

java 复制代码
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- 配置 DelegatingFilterProxy -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 其他配置 -->
</web-app>
2. 配置 Spring Bean

在 Spring 的配置文件中,我们定义 UserServiceCustomSecurityFilter Bean,并使用依赖注入。

applicationContext.xml 示例

java 复制代码
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
       xmlns:sec="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- 配置 Spring Security -->
    <sec:http auto-config="true">
        <sec:intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
        <sec:form-login login-page="/login" default-target-url="/home" />
        <sec:logout logout-success-url="/login?logout" />
    </sec:http>

    <sec:authentication-manager>
        <sec:authentication-provider>
            <sec:user-service>
                <sec:user name="user" password="password" authorities="ROLE_USER" />
                <sec:user name="admin" password="password" authorities="ROLE_ADMIN" />
            </sec:user-service>
        </sec:authentication-provider>
    </sec:authentication-manager>
</beans>

这样配置后,所有的 HTTP 请求都会经过 DelegatingFilterProxy,它会将请求委托给 Spring 容器中的 Spring Security 过滤器链,完成权限验证和安全控制

(困惑)实际上 springSecurityFilterChain 是 Spring Security 内部自动配置的一个 Bean,具体如何配置和工作如下:

1. DelegatingFilterProxyspringSecurityFilterChain

在使用 DelegatingFilterProxy 时,它会在 Spring 容器中查找一个名为 springSecurityFilterChain 的 Bean。这个 Bean 是由 Spring Security 自动配置的,不需要你显式地在配置中定义。Spring Security 在启动时会自动创建这个 Bean,并将它注册为过滤器链。

所以整个请求流程

  • 请求到达 Servlet 容器

    • 当客户端发起请求时,Servlet 容器开始处理这个请求。
  • 查找匹配的过滤器

    • Servlet 容器根据 web.xml 中的 <filter-mapping> 配置来决定哪些过滤器需要应用于这个请求。在你的配置中,所有的请求都匹配 /*,因此都会经过名为 customSecurityFilter 的过滤器。
java 复制代码
<filter-mapping>
    <filter-name>customSecurityFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

调用 DelegatingFilterProxy

  • Servlet 容器找到名为 customSecurityFilter 的过滤器,并创建 DelegatingFilterProxy 的实例。此时,DelegatingFilterProxy 并不直接处理请求,而是作为一个代理来转发请求。
java 复制代码
<filter>
    <filter-name>customSecurityFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
  1. 委托给 Spring 容器中的 Bean

    • DelegatingFilterProxy 使用 filter-name(即 customSecurityFilter)来查找 Spring 容器中的同名 Bean。在 Spring 容器中,customSecurityFilter 是一个实际的过滤器 Bean。
    • DelegatingFilterProxy 会调用 Spring 容器中的 customSecurityFilter Bean 的 doFilter 方法。这样,Spring 容器中的 Bean 就可以处理请求,并利用 Spring 的依赖注入等功能。
  2. 执行过滤器逻辑

    • customSecurityFilter Bean 处理请求。它可以依赖于其他 Spring 管理的 Bean,比如服务层的组件等。

图解流程

  1. 客户端请求 → 2. Servlet 容器 → 3. 查找 DelegatingFilterProxy → 4. DelegatingFilterProxy 查找 Spring 容器中的 customSecurityFilter Bean → 5. customSecurityFilter Bean 执行过滤器逻辑 → 6. 继续处理请求或返回响应
java 复制代码
客户端请求
     ↓
Servlet 容器
     ↓
DelegatingFilterProxy(代理)
     ↓
Spring 容器中的 customSecurityFilter Bean
     ↓
执行过滤器逻辑
     ↓
继续处理请求或返回响应

DelegatingFilterProxy 确实是通过 filter-name 来查找 Spring 容器中的同名 Bean

查找 Spring Bean

DelegatingFilterProxyinit 方法中,它会根据 filter-name 找到 Spring 容器中的相应 Bean。这个过程包括:

  • 获取过滤器名称 :通过 getFilterConfig().getFilterName() 获取配置的 filter-name
  • 从 Spring 容器中获取 Bean :使用 WebApplicationContextUtils 或类似的工具从 Spring 容器中查找与 filter-name 匹配的 Bean。
java 复制代码
@Override
public void init(FilterConfig filterConfig) throws ServletException {
    this.filterConfig = filterConfig;
    String beanName = filterConfig.getFilterName();
    ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
    this.delegate = (Filter) applicationContext.getBean(beanName);
}
  • 在上面的代码中,beanName 是从 filterConfig 获取的过滤器名称,然后从 Spring 容器中获取这个 Bean。

  • 委托请求处理

    doFilter 方法中,DelegatingFilterProxy 将请求转发给它从 Spring 容器中获得的 Bean:

java 复制代码
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    if (this.delegate == null) {
        throw new ServletException("Delegate Filter not initialized");
    }
    this.delegate.doFilter(request, response, chain);
}
  1. 这里,this.delegate 是从 Spring 容器中获取的实际过滤器 Bean,它的 doFilter 方法被调用来处理请求。

总结

  1. filter-name :在 web.xml 中配置的 filter-name 用于标识 DelegatingFilterProxy 要代理的 Spring Bean 名称。
  2. Spring 容器DelegatingFilterProxy 使用这个名称从 Spring 容器中查找实际的过滤器 Bean。
  3. 委托处理 :找到 Bean 后,DelegatingFilterProxy 将请求委托给这个 Bean 来处理。

通过这些源码中的实现细节,可以确认 DelegatingFilterProxy 是如何使用 filter-name 查找和委托请求给 Spring 容器中的 Bean 的。

DelegatingFilterProxy 和普通的 Servlet 过滤器相比

普通的 Servlet 过滤器

在传统的 Servlet 过滤器中,你会直接实现 javax.servlet.Filter 接口,并在 doFilter 方法中处理请求。例如:

java 复制代码
public class CustomFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化代码
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 过滤器逻辑
        chain.doFilter(request, response); // 继续传递请求
    }

    @Override
    public void destroy() {
        // 清理资源
    }
}

web.xml 中,你会配置这个过滤器,如下:

java 复制代码
<filter>
    <filter-name>customFilter</filter-name>
    <filter-class>com.example.CustomFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>customFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

DelegatingFilterProxy

DelegatingFilterProxy 是 Spring 提供的一个特殊过滤器,它的工作原理略有不同。它的主要目的是将请求转发给 Spring 容器中的实际过滤器 Bean,而不是直接处理请求。DelegatingFilterProxy 实现了 javax.servlet.Filter 接口,但它的 doFilter 方法并不会直接处理请求,而是将请求委托给 Spring 管理的 Bean。

DelegatingFilterProxy 的工作流程

  1. 初始化

    • init 方法中,DelegatingFilterProxy 根据 filter-name 从 Spring 容器中查找一个 Bean。这个 Bean 实现了 javax.servlet.Filter 接口,并且是由 Spring 容器管理的。
java 复制代码
@Override
public void init(FilterConfig filterConfig) throws ServletException {
    this.filterConfig = filterConfig;
    String beanName = filterConfig.getFilterName();
    ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
    this.delegate = (Filter) applicationContext.getBean(beanName);
}

2.请求处理

doFilter 方法中,DelegatingFilterProxy 将请求转发给 Spring 容器中的实际 Bean,而不是直接处理请求。

java 复制代码
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    if (this.delegate == null) {
        throw new ServletException("Delegate Filter not initialized");
    }
    this.delegate.doFilter(request, response, chain);
}

这里,this.delegate 是从 Spring 容器中获取的实际过滤器 Bean,它会处理请求。

  • 清理资源

    • destroy 方法中,DelegatingFilterProxy 不会执行任何操作,因为它不直接持有资源。
  • 普通 Servlet 过滤器 :直接实现 Filter 接口,处理请求的逻辑在 doFilter 方法中实现。

  • 依赖注入:可以使用 Spring 的依赖注入功能来管理过滤器。

  • Spring 管理:将过滤器的配置和管理转移到 Spring 容器中,享受 Spring 提供的其他功能(如事务管理、AOP)。

  • 这里,this.delegate 是从 Spring 容器中获取的实际过滤器 Bean,它会处理请求。

  • 清理资源

    • destroy 方法中,DelegatingFilterProxy 不会执行任何操作,因为它不直接持有资源。
  • 普通 Servlet 过滤器 :直接实现 Filter 接口,处理请求的逻辑在 doFilter 方法中实现。

  • DelegatingFilterProxy:作为一个代理,负责将请求委托给 Spring 容器中的实际过滤器 Bean,利用 Spring 的依赖注入等功能。

  • 依赖注入:可以使用 Spring 的依赖注入功能来管理过滤器。

  • Spring 管理:将过滤器的配置和管理转移到 Spring 容器中,享受 Spring 提供的其他功能(如事务管理、AOP)。

相关推荐
佛祖让我来巡山9 天前
小明网站双登录系统实现——微信授权登录+用户名密码登录完整指南
oauth2·springsecurity·微信授权登录
佛祖让我来巡山9 天前
Spring Security 鉴权流程与过滤器链深度剖析
springsecurity·authenticationmanager
佛祖让我来巡山10 天前
大型项目基于Spring Security的登录鉴权与数据权限控制完整方案
springsecurity·保姆级鉴权·大型项目登录认证
佛祖让我来巡山10 天前
Spring Security前后端分离接入流程保姆级教程
权限校验·springsecurity·登录认证
佛祖让我来巡山10 天前
Spring Security 认证流程闭环与调用链路详解
springsecurity·authenticationmanager
佛祖让我来巡山11 天前
小明的Spring Security入门到深入实战
springsecurity
佛祖让我来巡山12 天前
⚠️登录认证功能的成长过程:整体概述
安全·登录·springsecurity·登录认证·认证授权
洛克大航海1 个月前
9-SpringCloud-服务网关 Gateway-高级特性之 Filter-2
java·spring cloud·gateway·filter
洛克大航海1 个月前
9-SpringCloud-服务网关 Gateway-高级特性之 Filter-1
spring·spring cloud·gateway·filter
清静诗意1 个月前
【Django FilterSet 深入解析】类属性过滤器与 Meta.fields 的关系详解(附源码分析)
django·filter