责任链模式在spring security过滤器链中的应用

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象按照顺序处理请求,并且每个对象可以选择自己是否处理该请求或将其传递给下一个对象。

在Spring Security中,责任链模式得到了广泛应用,特别是在其过滤器链(Filter Chain)机制中。

一、Spring Security过滤器链概述

Spring Security中的过滤器链是保护Web应用程序的核心组件之一。它是一条由多个过滤器组成的序列,这些过滤器按照特定顺序执行,用于处理HTTP请求和响应。每当客户端向应用程序发送请求时,请求首先会经过Spring Security的过滤器链。过滤器链中的过滤器会按顺序执行,每个过滤器都有机会处理请求和响应。如果过滤器允许请求继续,则请求会被转发到下一个过滤器或最终到达应用程序的控制器。

二、责任链模式在过滤器链中的应用 

  • 过滤器链的构成

    • Spring Security的过滤器链包含多种过滤器,如:UsernamePasswordAuthenticationFilter(用于处理基于用户名和密码的身份验证)、AbstractAuthenticationProcessingFilter(抽象类,是大多数身份验证过滤器的基类)、SecurityContextPersistenceFilter(负责加载和保存SecurityContext)、RememberMeAuthenticationFilter(处理基于“记住我”功能的身份验证)、CsrfFilter(处理跨站请求伪造保护)以及FilterSecurityInterceptor(执行访问决策)等。
  • 责任链模式的实现

    • 在Spring Security中,每个过滤器都实现了特定的安全功能,并且它们按照配置的顺序串联在一起,形成了一个过滤器链。
    • 当请求到达时,它首先被传递给链中的第一个过滤器。该过滤器会根据其逻辑判断是否需要处理该请求。如果需要,则进行处理;如果不需要或处理完成后需要继续传递,则将该请求传递给链中的下一个过滤器。
    • 这种机制允许每个过滤器专注于自己的安全功能,而无需关心其他过滤器的实现细节。同时,它也提供了更大的灵活性和可扩展性,因为可以通过添加、删除或重新排序过滤器来轻松地修改安全策略。
  • 关键过滤器的功能

    • UsernamePasswordAuthenticationFilter:用于处理基于用户名和密码的身份验证。它通常处理POST请求到/login端点。
    • SecurityContextPersistenceFilter:负责加载和保存SecurityContext。SecurityContext包含当前用户的安全上下文,如已认证的用户主体。
    • FilterSecurityInterceptor:执行访问决策。它根据配置的AccessDecisionManagerAccessDecisionVoter来决定用户是否有权访问某个资源。

三、自定义过滤器

在Spring Security中,自定义过滤器的实现是责任链模式的一个典型应用。通过创建并注册自定义过滤器,你可以将特定的安全逻辑插入到过滤器链中,从而在请求处理过程中执行额外的操作。

以下是一个简单的示例,展示如何创建自定义过滤器并将其集成到Spring Security的过滤器链中。

假设我们需要创建一个自定义过滤器,用于记录每个请求的URI和HTTP方法。以下是如何实现这个自定义过滤器并将其添加到Spring Security的过滤器链中的步骤。 

创建自定义过滤器

首先,你需要创建一个实现javax.servlet.Filter接口的类。在这个类中,你将覆盖doFilter方法以执行你的自定义逻辑。

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class CustomLoggingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化逻辑(可选)
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String uri = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();

        // 记录请求的URI和HTTP方法
        System.out.println("Request URI: " + uri + ", Method: " + method);

        // 将请求传递给过滤器链中的下一个过滤器
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 销毁逻辑(可选)
    }
}

注册自定义过滤器到Spring Security

接下来,你需要将自定义过滤器注册到Spring Security的过滤器链中。这通常是通过配置类来实现的。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(customLoggingFilter(), UsernamePasswordAuthenticationFilter.class)
            // 其他安全配置...
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin() // 如果使用表单登录,则启用它
            .and()
            .httpBasic(); // 启用HTTP Basic(可选)

        return http.build();
    }

    @Bean
    public CustomLoggingFilter customLoggingFilter() {
        return new CustomLoggingFilter();
    }
}

在这个配置类中,我们使用了HttpSecurity来配置Spring Security。通过调用addFilterBefore方法,我们将自定义过滤器CustomLoggingFilter添加到了UsernamePasswordAuthenticationFilter之前。这意味着在身份验证之前,我们的自定义过滤器将首先执行并记录请求的URI和HTTP方法。

运行应用程序

现在,当你运行应用程序并发送请求时,你应该会在控制台中看到自定义过滤器记录的请求信息。

 

在Spring Security中每个过滤器(包括自定义过滤器)都是链中的一个节点,它们按照配置的顺序依次执行。每个过滤器都有机会处理请求,并且可以选择将请求传递给链中的下一个过滤器或执行其他操作(如拒绝访问、重定向等)。这种机制使得Spring Security能够灵活地处理各种安全需求,同时保持了代码的清晰和可维护性。

 

### Spring Security 过滤器中的各个过滤器执行顺序 在Spring Security框架内,多个过滤器按照预定义的顺序排列并依次调用以完成一系列的安全控制任务。这些过滤器被设计成能够处理诸如身份验证、访问权限检查等功能,并且每一个都有独特的角色。 #### 默认情况下,Spring Security过滤器通常遵循如下顺序: 1. **WebAsyncManagerIntegrationFilter** 此过滤器用于支持异步请求下的安全上下文传播[^2]。 2. **SecurityContextPersistenceFilter** 负责保存和恢复`SecurityContextHolder`中的`SecurityContext`对象,在每次HTTP请求开始时初始化安全上下文,并在结束时清理它。 3. **HeaderWriterFilter** 添加必要的响应头来增强安全性,比如防止点击劫持(X-Frame-Options),设置缓存策略(Cache-Control)等。 4. **CsrfFilter** 实现跨站请求伪造保护机制,通过比较客户端提交的CSRF令牌与服务器端存储的一致性来进行防护。 5. **LogoutFilter** 处理用户的登出逻辑,当接收到匹配路径的POST请求时触发注销过程。 6. **UsernamePasswordAuthenticationFilter** 验证基于用户名/密码的身份凭证,默认绑定到/login URL上。 7. **DefaultLoginPageGeneratingFilter & DefaultLogoutPageGeneratingFilter** 当未提供自定义登录页面或退出页面时自动创建默认版本。 8. **ConcurrentSessionFilter** 控制同一用户的同时在线会话数量,超出限额则拒绝新连接。 9. **OAuth2LoginAuthenticationFilter, Saml2WebSsoAuthenticationFilter**, etc. 支持多种第三方认证方式如OAuth2/SAML SSO协议。 10. **RequestCacheAwareFilter** 如果之前存在重定向,则尝试从缓存中检索原始请求信息以便继续处理。 11. **SecurityContextHolderAwareRequestWrapperFilter** 将当前线程关联的安全上下文封装进HttpServletRequest对象中供后续使用。 12. **RememberMeAuthenticationFilter** 对于启用了记住我的服务,此过滤器会在成功登录后向浏览器发送持久化Cookie。 13. **AnonymousAuthenticationFilter** 若无其他形式的有效认证,则为匿名用户提供临时身份标识。 14. **SessionManagementFilter** 管理会话固定攻击风险以及强制单一会话等问题。 15. **ExceptionTranslationFilter** 捕获所有抛出自定义异常(如AccessDeniedException),并将它们转换成适当类型的HTTP错误状态码返回给客户端;同时也会处理来自下游过滤器未能解决的身份验证需求[^3]。 16. **FilterSecurityInterceptor (FSI)** 作为最后一个核心组件,负责实际执行资源级别的授权决策,即判断已认证主体是否有权访问指定URL模式所代表的目标资源。 以上就是典型的Spring Security过滤器条路及其工作次序描述。值得注意的是,开发者可以根据项目具体需求调整这个列表内的成员构成及位置关系,甚至添加额外定制化的过滤单元。 为了配置上述提到的各种过滤器,可以利用Java Config 或 XML命名空间的方式进行声明式编程。对于大多数现代应用程序而言,推荐采用前者——借助@EnableWebSecurity注解配合SecurityConfig类内部的方法注入实现灵活而强大的安全设定。 ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") // 定义受保护资源规则 .anyRequest().authenticated() // 其他任何请求都需要经过身份验证 .and() .formLogin(); // 开启表单登陆功能 } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jack_abu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值