Spring Security之默认的过滤器链及自定义Filter操作

Spring Security 是 Spring 框架中提供的安全管理框架,它是基于 Servlet 过滤器实现的。

默认的过滤器链

Spring Security 在初始化时会自动生成一整套默认的过滤器链,这些过滤器链是按顺序有序地执行的。因为每个过滤器链都有特定的功能和处理逻辑,对于一个用户的请求,在整个过滤器链中会按照顺序经过每一个过滤器链的处理。最终,要么返回请求的处理结果,要么由后续过滤器链继续处理。

默认的过滤器链中包含以下过滤器:

  1. WebAsyncManagerIntegrationFilter - 异步响应的过滤器
  2. SecurityContextPersistenceFilter - 安全上下文持久化过滤器
  3. HeaderWriterFilter - 响应头写入过滤器
  4. CsrfFilter - CSRF攻击过滤器
  5. LogoutFilter - 登出过滤器
  6. UsernamePasswordAuthenticationFilter - 用户名密码认证过滤器
  7. DefaultLoginPageGeneratingFilter - 默认登录页面生成过滤器
  8. DefaultLogoutPageGeneratingFilter - 默认登出页面生成过滤器
  9. BasicAuthenticationFilter - 基础认证过滤器
  10. RequestCacheAwareFilter - 缓存请求过滤器
  11. SecurityContextHolderAwareRequestFilter - 认证信息和请求信息关联过滤器
  12. AnonymousAuthenticationFilter - 匿名认证过滤器
  13. SessionManagementFilter - 会话管理过滤器
  14. ExceptionTranslationFilter - 异常处理过滤器
  15. FilterSecurityInterceptor - 过滤安全拦截器

自定义Filter操作的步骤

如果默认的过滤器链中没有满足我们需求的过滤器,我们可以自定义一个过滤器,并且将这个过滤器添加到默认的过滤器链中。下面是自定义Filter的要点步骤:

  1. 继承GenericFilterBean类,实现业务逻辑,并重写doFilter方法
public class MyFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        // do something...
        // 调用过滤器链的下一个过滤器
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
  1. 对过滤器进行配置,为过滤器添加 URL 匹配规则和执行顺序。将过滤器加入到 Spring Security 过滤器链中
@Configuration
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 添加自定义过滤器,并设置过滤器链中的执行顺序
        http.addFilterBefore(new MyFilter(), UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            .anyRequest()
            .permitAll();
    }
}

示例

  1. 通过自定义过滤器在请求头中添加 Token
public class TokenFilter extends GenericFilterBean {

    private static final String TOKEN_HEADER = "X-Token";
    private static final String TOKEN_VALUE = "XXXXX";

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.addHeader(TOKEN_HEADER, TOKEN_VALUE);
        filterChain.doFilter(request, response);
    }

}

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterAfter(new TokenFilter(), BasicAuthenticationFilter.class);
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and().httpBasic();
    }

}
  1. 通过自定义过滤器拦截特定的请求,实现限流功能
public class TokenBucketFilter extends GenericFilterBean {

    private static final int TOKEN_BUCKET_SIZE = 100;  // 令牌桶大小
    private static final AtomicLong TOKEN_COUNT = new AtomicLong(0);  // 当前令牌数

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if (TOKEN_COUNT.get() >= TOKEN_BUCKET_SIZE) {
            // 如果当前令牌数大于等于令牌桶大小,则返回 429 Too Many Requests 状态码
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        } else {
            // 如果当前令牌数小于令牌桶大小,将当前令牌数加 1
            TOKEN_COUNT.incrementAndGet();
            filterChain.doFilter(request, response);
        }
    }

}

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterAfter(new TokenBucketFilter(), BasicAuthenticationFilter.class);
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and().httpBasic();
    }

}

以上示例分别实现了 Token 认证和限流两种基本的自定义过滤器功能,用到的类和方法都是 Spring Security 框架本身的 API,对于开发者而言非常友好和易于使用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security之默认的过滤器链及自定义Filter操作 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java实现截取字符串的操作详解

    Java实现截取字符串的操作详解 Java是一种非常流行的编程语言,它内置了许多字符串操作函数,其中截取字符串也是其中一种常用的操作技能。本文旨在详细讲解Java实现截取字符串的操作,并提供两个示例进行说明。 什么是截取字符串? 截取字符串是指从一个字符串中抽取出一个子字符串。例如,有一个字符串“Hello world”,如果我们想要取出“Hello”这个子…

    Java 2023年5月26日
    00
  • Java实现在线预览的示例代码(openOffice实现)

    Java实现在线预览是许多Web应用程序开发中常用的技术之一。本文将讲解如何使用openOffice实现在线预览Java文档的方法。 前置条件 在开始本文之前,请确保您已经满足以下条件: 安装openOffice软件并启动该服务。 安装Java开发环境(JDK) 如果您使用的是Maven和Spring,您需要安装这些工具 实现步骤 导入依赖 如果您正在使用M…

    Java 2023年5月18日
    00
  • 基于slf4j日志MDC输出格式的问题

    针对”基于slf4j日志MDC输出格式的问题”,我会给出完整的攻略如下: 什么是MDC? 在程序日志输出中,MDC是最常用的工具之一,全称是Mapped Diagnostic Context,它的功能是为日志输出提供上下文信息,可以理解为是一种线程级别的context。通常情况下,我们可以使用MDC来输出一些和程序运行情况相关的信息,比如用户ID、IP地址等…

    Java 2023年5月26日
    00
  • JSON.toJSONString()空字段不忽略修改的问题

    “JSON.toJSONString()空字段不忽略修改的问题”指的是在Java中使用JSON.toJSONString()方法转换对象为JSON字符串时,如果对象中包含空字段的属性,转换后的JSON字符串默认会保留这些空字段,并以null值表示。而有时候我们希望转换后的JSON字符串不包含这些空字段,因此需要进行一些额外的处理。 解决该问题的方法有两种,分…

    Java 2023年5月26日
    00
  • Java虚拟机JVM性能优化(一):JVM知识总结

    在进行Java虚拟机JVM性能优化前,我们需要全面了解JVM的相关知识,这篇文章将对JVM进行总结,从而帮助我们提高程序性能。 JVM的定义及作用 JVM是Java虚拟机的缩写,它是Java程序能够在不同平台上运行的基础。JVM通过将Java字节码解释成平台相关的机器语言来实现这一功能,从而使Java程序能够在不同的操作系统上都能正常运行。 JVM架构 JV…

    Java 2023年5月19日
    00
  • java实现堆排序以及时间复杂度的分析

    下面我会详细讲解“java实现堆排序以及时间复杂度的分析”的完整攻略,包括定义、算法步骤、实现过程和时间复杂度的分析。 定义 堆排序是一种树形选择排序,它的排序过程类似于选择排序,建立在堆的基础之上。堆是一个近似完全二叉树的结构,并同时满足堆积的性质: 父节点的键值总是大于或等于任何一个子节点的键值。 每个节点的左右子树都是一个堆。 算法步骤 创建一个初始数…

    Java 2023年5月19日
    00
  • java eclipse 启动参数

    Java Eclipse启动参数是在启动Eclipse时传递给JVM的一组特殊参数,用于设置系统的属性,配置内存和调试信息等。以下是详细的Java Eclipse启动参数攻略: 设置Java版本 在启动Eclipse时,可以通过在eclipse.ini文件中设置vm参数来指定使用的Java版本。例如,假设Eclipse安装目录下的eclipse.ini文件如…

    Java 2023年6月15日
    00
  • java.net.ConnectException: Connection refused问题解决办法

    当Java应用程序尝试连接到另一个应用程序或服务器但无法建立连接时,你可能会遇到 java.net.ConnectException: Connection refused 异常。这种情况通常表示目标主机拒绝连接或者连接超时。下面是解决此问题的完整攻略: 1. 检查目标服务器/应用程序是否正在运行 首先,你需要确保你所连接的应用程序或服务器正在运行。 如果目…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部