设计模式:责任链模式(Spring Security)

目录

一、核心角色对应(责任链模式)

二、核心架构:双层责任链设计

[1. 外层:FilterChainProxy(全局过滤器入口)](#1. 外层:FilterChainProxy(全局过滤器入口))

[2. 内层:SecurityFilterChain(具体过滤器链)](#2. 内层:SecurityFilterChain(具体过滤器链))

三、核心流程(以表单登录为例)

关键特点:

四、代码示例:自定义过滤器链

[步骤 1:自定义认证过滤器(具体处理者)](#步骤 1:自定义认证过滤器(具体处理者))

[步骤 2:配置过滤器链(责任链管理器)](#步骤 2:配置过滤器链(责任链管理器))

[步骤 3:核心业务(Controller,责任链终点)](#步骤 3:核心业务(Controller,责任链终点))

五、核心过滤器(内置具体处理者)

六、责任链的核心实现(源码简化)

[1. FilterChainProxy(外层管理器)](#1. FilterChainProxy(外层管理器))

[2. 关键逻辑:](#2. 关键逻辑:)

[七、Spring Security 责任链的核心特点](#七、Spring Security 责任链的核心特点)

[1. 高度可定制](#1. 高度可定制)

[2. 中断性与容错性](#2. 中断性与容错性)

[3. 解耦性](#3. 解耦性)

八、典型应用场景

[九、与 Spring MVC 拦截器链的区别](#九、与 Spring MVC 拦截器链的区别)

总结


Spring Security 的核心架构完全基于责任链模式 设计,其核心载体是 过滤器链(SecurityFilterChain ------ 将认证、授权、防护等安全逻辑拆分为独立的过滤器(Filter),请求沿过滤器链按序执行,每个过滤器负责单一安全职责,最终实现完整的安全校验流程。

核心目标:将复杂的安全逻辑解耦为可插拔的过滤器组件,支持灵活扩展和定制(如新增验证码校验、JWT 认证、接口限流等)

一、核心角色对应(责任链模式)

责任链模式角色 Spring Security 对应实现 核心职责
抽象处理者(Handler) javax.servlet.Filter(Servlet 过滤器)/ OncePerRequestFilter 定义过滤器核心方法 doFilter(),约定请求处理规则(Spring Security 过滤器多继承 OncePerRequestFilter 保证单次请求仅执行一次)
具体处理者 内置过滤器(如 UsernamePasswordAuthenticationFilterJwtAuthenticationFilter)/ 自定义过滤器 实现特定安全逻辑(认证、授权、CSRF 防护等),通过 chain.doFilter() 传递请求
责任链管理器 FilterChainProxy + SecurityFilterChain FilterChainProxy 是顶级入口,匹配请求对应的 SecurityFilterChain,触发过滤器链执行
请求对象 HttpServletRequest/HttpServletResponse 被过滤器链处理的核心对象
最终处理者 目标资源(Controller / 静态资源) 过滤器链执行完成后,请求传递到核心业务逻辑

二、核心架构:双层责任链设计

Spring Security 的责任链分为两层,保证 "多规则适配 + 顺序执行":

1. 外层:FilterChainProxy(全局过滤器入口)

FilterChainProxy 是 Spring Security 注册到 Servlet 容器的唯一过滤器(通过 DelegatingFilterProxy 适配),其核心作用是:

  • 根据请求路径匹配对应的 SecurityFilterChain(支持多套过滤器链,如 /api/** 一套、/admin/** 另一套);
  • 触发匹配到的 SecurityFilterChain 执行。

2. 内层:SecurityFilterChain(具体过滤器链)

每个 SecurityFilterChain 包含一组有序的过滤器(List<Filter>),是真正执行安全逻辑的责任链,例如:

plaintext

复制代码
UsernamePasswordAuthenticationFilter(表单登录认证)→ 
BasicAuthenticationFilter(Basic 认证)→ 
JwtAuthenticationFilter(JWT 认证)→ 
FilterSecurityInterceptor(授权校验)→ 
ExceptionTranslationFilter(异常处理)

三、核心流程(以表单登录为例)

plaintext

复制代码
客户端请求 → 
  Tomcat → DelegatingFilterProxy → FilterChainProxy → 
    匹配 SecurityFilterChain → 执行过滤器链:
      1. CsrfFilter(CSRF 防护)→ 
      2. UsernamePasswordAuthenticationFilter(表单登录认证)→ 
      3. BasicAuthenticationFilter(Basic 认证,跳过)→ 
      4. FilterSecurityInterceptor(授权校验)→ 
      5. ExceptionTranslationFilter(异常处理,无异常则跳过)→ 
  传递到 DispatcherServlet → Controller(核心业务)

关键特点:

  • 顺序性:过滤器按固定顺序执行(可通过配置调整),例如 "认证过滤器必须在授权过滤器前执行";
  • 中断性 :过滤器可中断链(如认证失败直接返回 401,不调用 chain.doFilter());
  • 匹配性 :不同请求路径可匹配不同过滤器链(如 /login 走表单登录链,/api 走 JWT 认证链)。

四、代码示例:自定义过滤器链

步骤 1:自定义认证过滤器(具体处理者)

实现 JWT 认证过滤器,作为责任链的具体处理者:

java

运行

复制代码
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 1. 提取 Token
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            filterChain.doFilter(request, response); // 无 Token,传递给下一个过滤器
            return;
        }
        token = token.substring(7);

        // 2. 校验 Token
        try {
            String username = jwtTokenProvider.extractUsername(token);
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                // 3. 认证通过,存入 SecurityContext
                Authentication authentication = jwtTokenProvider.getAuthentication(token);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                System.out.println("JwtAuthenticationFilter:JWT 认证通过,用户:" + username);
            }
        } catch (Exception e) {
            // 认证失败,中断链(返回 401)
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("JWT 认证失败:" + e.getMessage());
            return;
        }

        // 4. 传递给下一个过滤器
        filterChain.doFilter(request, response);
    }
}

步骤 2:配置过滤器链(责任链管理器)

通过 SecurityFilterChain 构建自定义责任链,指定过滤器顺序:

java

运行

复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;
    @Autowired
    private CustomAccessDeniedHandler accessDeniedHandler; // 自定义授权失败处理器

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            // 关闭默认的 CSRF(测试环境,生产需开启)
            .csrf(csrf -> csrf.disable())
            // 配置请求授权规则
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login").permitAll() // 登录接口放行
                .requestMatchers("/api/admin/**").hasRole("ADMIN") // 管理员接口需 ADMIN 角色
                .anyRequest().authenticated() // 其他请求需认证
            )
            // 异常处理
            .exceptionHandling(ex -> ex
                .accessDeniedHandler(accessDeniedHandler) // 授权失败处理
                .authenticationEntryPoint((request, response, authException) -> {
                    // 认证失败处理
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                    response.getWriter().write("请先认证");
                })
            )
            // 添加自定义过滤器:插入到 UsernamePasswordAuthenticationFilter 之后
            .addFilterAfter(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    // 认证管理器(用于处理用户认证)
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

    // 密码编码器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

步骤 3:核心业务(Controller,责任链终点)

java

运行

复制代码
@RestController
@RequestMapping("/api")
public class UserController {
    @GetMapping("/user")
    public String getUser() {
        return "普通用户接口";
    }

    @GetMapping("/admin/user")
    public String getAdminUser() {
        return "管理员接口";
    }
}

五、核心过滤器(内置具体处理者)

Spring Security 内置了数十个过滤器,覆盖所有核心安全场景,以下是最常用的:

过滤器 核心职责 执行顺序(关键)
CsrfFilter CSRF 防护,验证 CSRF Token 靠前(先防护后认证)
UsernamePasswordAuthenticationFilter 表单登录认证,处理 /login 请求的用户名密码 认证类过滤器核心
BasicAuthenticationFilter Basic 认证,解析请求头中的 Authorization: Basic xxx 表单认证之后
JwtAuthenticationFilter JWT 认证(需自定义 / 引入 spring-security-oauth2) 可插入到认证过滤器链
FilterSecurityInterceptor 授权校验,匹配 @PreAuthorize/ 角色 / 权限规则 认证之后(最后一个核心过滤器)
ExceptionTranslationFilter 捕获安全异常(如 AuthenticationException/AccessDeniedException),转换为 HTTP 响应 授权过滤器之前
LogoutFilter 处理登出请求,清理 SecurityContext 认证过滤器之前

六、责任链的核心实现(源码简化)

1. FilterChainProxy(外层管理器)

java

运行

复制代码
public class FilterChainProxy extends GenericFilterBean {
    private List<SecurityFilterChain> filterChains;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        // 1. 匹配当前请求对应的 SecurityFilterChain
        SecurityFilterChain filterChain = getMatchingFilterChain(req, res);
        if (filterChain == null) {
            chain.doFilter(req, res); // 无匹配链,直接传递
            return;
        }

        // 2. 执行匹配到的过滤器链
        VirtualFilterChain virtualFilterChain = new VirtualFilterChain(chain, filterChain.getFilters());
        virtualFilterChain.doFilter(req, res);
    }

    // 内部类:封装具体过滤器链的执行
    private static class VirtualFilterChain implements FilterChain {
        private final FilterChain originalChain;
        private final List<Filter> filters;
        private int currentPosition = 0;

        public VirtualFilterChain(FilterChain originalChain, List<Filter> filters) {
            this.originalChain = originalChain;
            this.filters = filters;
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
            if (currentPosition == filters.size()) {
                // 所有过滤器执行完成,传递到原始链(DispatcherServlet)
                originalChain.doFilter(request, response);
                return;
            }

            // 按顺序执行下一个过滤器
            currentPosition++;
            Filter nextFilter = filters.get(currentPosition - 1);
            nextFilter.doFilter(request, response, this);
        }
    }
}

2. 关键逻辑:

  • VirtualFilterChain 是责任链的核心执行器,通过 currentPosition 记录当前执行的过滤器索引;
  • 每个过滤器执行完后调用 virtualFilterChain.doFilter(),实现请求的 "链式传递";
  • 所有过滤器执行完成后,才会调用 originalChain.doFilter() 传递到 DispatcherServlet。

七、Spring Security 责任链的核心特点

1. 高度可定制

  • 顺序调整 :通过 addFilterBefore()/addFilterAfter()/addFilterAt() 调整过滤器顺序(如将 JWT 过滤器插入到表单认证过滤器之后);
  • 链的拆分 :多套 SecurityFilterChain 适配不同路径的安全规则(如前台 / 后台不同认证方式);
  • 过滤器扩展 :自定义过滤器只需继承 OncePerRequestFilter,注册到链中即可,无需修改原有逻辑。

2. 中断性与容错性

  • 中断链 :过滤器可通过 "不调用 chain.doFilter()" 中断请求(如认证失败直接返回 401);
  • 异常处理ExceptionTranslationFilter 捕获链中异常,保证单一异常出口,避免链中断导致的资源泄漏。

3. 解耦性

  • 每个过滤器仅关注单一职责(如认证、授权、CSRF),符合 "单一职责原则";
  • 核心业务(Controller)无需耦合安全逻辑,通过过滤器链透明增强。

八、典型应用场景

  1. 多认证方式:同时支持表单登录、JWT 认证、OAuth2 认证(不同过滤器处理);
  2. 精细化授权 :基于角色(hasRole)、权限(hasPermission)、IP 白名单的授权校验;
  3. 安全防护:CSRF 防护、XSS 过滤、接口限流(自定义过滤器实现);
  4. 异常统一处理:认证 / 授权失败返回标准化 JSON 响应;
  5. 第三方集成:集成 CAS、LDAP 等认证体系(新增对应过滤器)。

九、与 Spring MVC 拦截器链的区别

维度 Spring Security 过滤器链 Spring MVC HandlerInterceptor 链
核心目的 安全逻辑(认证、授权、防护) 通用请求增强(日志、参数处理)
执行时机 DispatcherServlet 之前(Servlet 容器层) DispatcherServlet 内部
扩展能力 可拦截所有 Web 请求(包括静态资源) 仅拦截 Controller 请求
依赖 原生 Servlet Filter,无 Spring 依赖 依赖 Spring 上下文,可注入 Bean
中断方式 不调用 chain.doFilter() preHandle 返回 false

总结

Spring Security 是责任链模式在 "安全领域" 的极致落地:

  1. 核心载体FilterChainProxy + SecurityFilterChain 构成双层责任链,实现 "多规则匹配 + 顺序执行";
  2. 核心逻辑 :每个过滤器是独立的安全处理单元,通过 chain.doFilter() 传递请求,支持中断和扩展;
  3. 核心价值:将复杂的安全逻辑解耦为可插拔的过滤器,适配不同场景的安全需求(如单体应用、微服务、前后端分离);
  4. 扩展关键 :自定义过滤器只需继承 OncePerRequestFilter,通过 addFilterBefore/After 插入到责任链中,无需修改框架源码。

掌握这一机制,是定制 Spring Security 安全规则(如 JWT 认证、自定义授权)的核心前提。

相关推荐
阿拉斯攀登2 小时前
设计模式:责任链模式(springmvc应用)
设计模式·springmvc·责任链模式
阿拉斯攀登2 小时前
设计模式:命令模式
设计模式·命令模式
阿闽ooo3 小时前
抽象工厂模式实战:用C++打造家具生产系统(附UML图与完整代码)
c++·设计模式·抽象工厂模式·uml
是店小二呀3 小时前
DanceGRPO+FLUX:多模态生成强化学习模型的高效
设计模式
明洞日记3 小时前
【设计模式手册022】抽象工厂模式 - 创建产品家族
java·设计模式·抽象工厂模式
阿拉斯攀登4 小时前
设计模式:命令模式(Spring MVC中的实践)
设计模式·springmvc·命令模式
明洞日记4 小时前
【设计模式手册021】代理模式 - 如何控制对象访问
设计模式·系统安全·代理模式
山沐与山4 小时前
【设计模式】Python策略模式:从入门到实战
python·设计模式·策略模式
阿拉斯攀登4 小时前
设计模式:责任链模式(mybatis数据权限实现)
设计模式·mybatis·责任链模式