0

0

Spring Boot Security:为特定URL模式定制JWT认证过滤器

心靈之曲

心靈之曲

发布时间:2025-07-08 19:34:12

|

972人浏览过

|

来源于php中文网

原创

spring boot security:为特定url模式定制jwt认证过滤器

针对Spring Boot Security中JWT过滤器默认应用于所有URL的问题,本文详细阐述如何通过扩展AbstractAuthenticationProcessingFilter并结合RequestMatcher,实现JWT过滤器仅对 /api/** 等指定URL模式生效,从而提供更精细化的安全控制。通过此方法,开发者可以精确地控制哪些请求需要JWT认证,避免不必要的性能开销和逻辑复杂性。

在Spring Boot应用程序中集成JWT(JSON Web Token)进行认证时,一个常见的需求是只对特定URL模式的请求应用JWT过滤器,而不是所有请求。默认情况下,如果直接使用http.addFilterBefore(customJwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class),该自定义过滤器可能会在所有请求进入UsernamePasswordAuthenticationFilter之前被执行,这在某些场景下可能不是最优解,例如,对于公开的API或静态资源,我们不希望它们经过JWT认证逻辑。

为了实现对特定URL模式的精确过滤,Spring Security提供了AbstractAuthenticationProcessingFilter抽象类和RequestMatcher接口,它们是解决此类问题的关键。

核心概念解析

  1. AbstractAuthenticationProcessingFilter: 这是Spring Security中用于处理特定认证请求的抽象基类。它在内部持有一个RequestMatcher实例,只有当请求与该RequestMatcher匹配时,过滤器才会尝试进行认证处理(即调用attemptAuthentication方法)。这使得我们可以将认证逻辑与请求路径解耦,实现按需认证。

  2. RequestMatcher: 这是一个核心接口,定义了如何判断一个HttpServletRequest是否匹配某种规则。Spring Security提供了多种内置实现,例如:

    • AntPathRequestMatcher: 基于Ant风格路径模式(如/api/**, /users/*)进行匹配。
    • RegexRequestMatcher: 基于正则表达式进行匹配。
    • OrRequestMatcher: 将多个RequestMatcher通过逻辑或(OR)组合。
    • AndRequestMatcher: 将多个RequestMatcher通过逻辑与(AND)组合。 通过灵活运用这些匹配器,我们可以构建复杂的URL匹配逻辑。

实现步骤

1. 创建定制JWT认证过滤器

首先,我们需要修改原有的CustomJwtAuthenticationFilter,使其继承自AbstractAuthenticationProcessingFilter,并在构造函数中接收一个RequestMatcher。

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CustomJwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    // 构造函数,接收一个RequestMatcher,该匹配器定义了哪些请求需要此过滤器处理
    public CustomJwtAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
        super(requiresAuthenticationRequestMatcher);
    }

    // 实际的认证逻辑
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        // 从请求中提取JWT令牌的逻辑
        String token = extractJwtFromRequest(request);

        if (token == null) {
            // 如果没有令牌,则抛出认证异常,由AuthenticationEntryPoint处理
            throw new BadCredentialsException("No JWT token found in request.");
        }

        // 假设JwtAuthenticationToken是一个自定义的Authentication实现,
        // 包含了JWT令牌信息,等待AuthenticationManager处理
        JwtAuthenticationToken authenticationToken = new JwtAuthenticationToken(token);

        // 将令牌提交给AuthenticationManager进行认证
        // AuthenticationManager会找到对应的AuthenticationProvider来验证令牌
        return this.getAuthenticationManager().authenticate(authenticationToken);
    }

    // 辅助方法:从请求中提取JWT令牌
    private String extractJwtFromRequest(HttpServletRequest request) {
        // 示例:从Authorization头中提取Bearer Token
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7); // 移除"Bearer "前缀
        }
        return null;
    }

    // 可以选择性地覆盖successfulAuthentication和unsuccessfulAuthentication方法
    // 来处理认证成功或失败后的逻辑,例如设置安全上下文或记录日志。
}

注意:JwtAuthenticationToken 和处理JWT令牌的AuthenticationProvider需要您自行实现。这里主要关注过滤器的结构。

有道智云AI开放平台
有道智云AI开放平台

有道智云AI开放平台

下载

2. 定义请求匹配器

为了让JWT过滤器仅作用于/api/**路径,我们可以使用AntPathRequestMatcher。

import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

// ...
// 在您的Security配置类中或单独定义
RequestMatcher apiPathsMatcher = new AntPathRequestMatcher("/api/**");

3. 集成到Spring Security配置

最后,在您的Spring Security配置类(通常是继承WebSecurityConfigurerAdapter的类)中,将这个定制的JWT过滤器添加到过滤器链中。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.AuthenticationEntryPoint; // 假设您有自定义的认证入口点

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService; // 假设您有UserDetailsService
    private final AuthenticationEntryPoint jwtAuthenticationEntryPoint; // 假设您有JWT认证入口点

    public SecurityConfig(UserDetailsService userDetailsService, AuthenticationEntryPoint jwtAuthenticationEntryPoint) {
        this.userDetailsService = userDetailsService;
        this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置您的AuthenticationManager,例如使用UserDetailsService和密码编码器
        auth.userDetailsService(userDetailsService);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        // 暴露AuthenticationManager为Bean,供CustomJwtAuthenticationFilter使用
        return super.authenticationManagerBean();
    }

    // 定义CustomJwtAuthenticationFilter为Bean
    @Bean
    public CustomJwtAuthenticationFilter customJwtAuthenticationFilter() throws Exception {
        // 创建一个匹配器,指定只有/api/**路径的请求才会被此JWT过滤器处理
        AntPathRequestMatcher apiMatcher = new AntPathRequestMatcher("/api/**");
        CustomJwtAuthenticationFilter filter = new CustomJwtAuthenticationFilter(apiMatcher);
        // 必须设置AuthenticationManager,因为AbstractAuthenticationProcessingFilter需要它来执行认证
        filter.setAuthenticationManager(authenticationManagerBean());
        // 可以选择性设置认证成功/失败处理器
        // filter.setAuthenticationSuccessHandler(...)
        // filter.setAuthenticationFailureHandler(...)
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable() // 禁用CSRF,因为JWT通常是无状态的
            .authorizeRequests()
                // 确保/api/**路径需要认证。当请求到达这些路径时,如果尚未认证,
                // customJwtAuthenticationFilter会尝试处理
                .antMatchers("/api/**").authenticated()
                // 其他路径可以设置为permitAll()或根据需求配置
                .antMatchers("/users", "/login", "/").permitAll()
                .anyRequest().authenticated() // 任何其他未匹配的请求也需要认证
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // JWT是无状态的
            .and()
            .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint) // 未认证或认证失败的入口点
                .accessDeniedPage("/403") // 访问被拒绝的页面
            .and()
            // 将自定义的JWT过滤器添加到UsernamePasswordAuthenticationFilter之前
            // CustomJwtAuthenticationFilter现在只处理/api/**路径
            .addFilterBefore(customJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

在上述配置中,antMatchers("/api/**").authenticated() 确保了所有/api/**路径的请求都需要认证。当请求匹配/api/**时,customJwtAuthenticationFilter会尝试提取并验证JWT令牌。如果令牌有效,请求将继续处理;否则,jwtAuthenticationEntryPoint将介入处理认证失败。对于其他未匹配/api/**的路径,customJwtAuthenticationFilter根本不会被触发,从而实现了精确的过滤。

注意事项

  1. AuthenticationManager的注入与设置:AbstractAuthenticationProcessingFilter需要一个AuthenticationManager来委托实际的认证过程。因此,您必须通过@Bean注解将authenticationManagerBean()暴露为一个Bean,并在创建CustomJwtAuthenticationFilter实例时将其设置进去。
  2. 过滤器链顺序:addFilterBefore(customJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)的顺序至关重要。它确保了在Spring Security默认的表单登录过滤器之前,我们的JWT过滤器有机会处理请求。
  3. RequestMatcher的灵活性:除了AntPathRequestMatcher,您还可以根据需要使用OrRequestMatcher、AndRequestMatcher等组合多个匹配规则,以实现更复杂的URL过滤逻辑。例如,如果您想过滤/api/v1/**和/admin/**,可以使用new OrRequestMatcher(new AntPathRequestMatcher("/api/v1/**"), new AntPathRequestMatcher("/admin/**"))。
  4. 认证入口点(AuthenticationEntryPoint):当CustomJwtAuthenticationFilter尝试认证失败时(例如,没有提供令牌或令牌无效),它会抛出AuthenticationException。此时,authenticationEntryPoint会负责处理这个异常,通常是返回一个401 Unauthorized响应。确保您的jwtAuthenticationEntryPoint能够正确处理这种情况。
  5. 无状态会话:JWT通常用于无状态认证,因此将sessionCreationPolicy设置为STATELESS是最佳实践,这会禁用Spring Security的会话管理,并确保每次请求都携带JWT进行认证。
  6. 错误处理:在attemptAuthentication方法中,如果无法提取或解析JWT,应抛出适当的AuthenticationException,让Spring Security的异常处理机制(通过AuthenticationEntryPoint)来统一处理。

总结

通过继承AbstractAuthenticationProcessingFilter并利用RequestMatcher,我们可以为Spring Boot Security中的JWT认证过滤器实现精准的URL模式匹配。这种方法不仅提高了应用程序的安全性,因为它只在必要时才执行认证逻辑,同时也优化了性能,避免了不必要的处理开销。掌握这种技术,能够帮助开发者构建更加健壮和高效的Spring Security认证体系。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

98

2025.08.06

spring boot框架优点
spring boot框架优点

spring boot框架的优点有简化配置、快速开发、内嵌服务器、微服务支持、自动化测试和生态系统支持。本专题为大家提供spring boot相关的文章、下载、课程内容,供大家免费下载体验。

135

2023.09.05

spring框架有哪些
spring框架有哪些

spring框架有Spring Core、Spring MVC、Spring Data、Spring Security、Spring AOP和Spring Boot。详细介绍:1、Spring Core,通过将对象的创建和依赖关系的管理交给容器来实现,从而降低了组件之间的耦合度;2、Spring MVC,提供基于模型-视图-控制器的架构,用于开发灵活和可扩展的Web应用程序等。

384

2023.10.12

Java Spring Boot开发
Java Spring Boot开发

本专题围绕 Java 主流开发框架 Spring Boot 展开,系统讲解依赖注入、配置管理、数据访问、RESTful API、微服务架构与安全认证等核心知识,并通过电商平台、博客系统与企业管理系统等项目实战,帮助学员掌握使用 Spring Boot 快速开发高效、稳定的企业级应用。

64

2025.08.19

Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性
Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性

Spring Boot 是一个基于 Spring 框架的 Java 开发框架,它通过 约定优于配置的原则,大幅简化了 Spring 应用的初始搭建、配置和开发过程,让开发者可以快速构建独立的、生产级别的 Spring 应用,无需繁琐的样板配置,通常集成嵌入式服务器(如 Tomcat),提供“开箱即用”的体验,是构建微服务和 Web 应用的流行工具。

11

2025.12.22

Java Spring Boot 微服务实战
Java Spring Boot 微服务实战

本专题深入讲解 Java Spring Boot 在微服务架构中的应用,内容涵盖服务注册与发现、REST API开发、配置中心、负载均衡、熔断与限流、日志与监控。通过实际项目案例(如电商订单系统),帮助开发者掌握 从单体应用迁移到高可用微服务系统的完整流程与实战能力。

101

2025.12.24

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

403

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

528

2023.08.23

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 2.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.0万人学习

Sass 教程
Sass 教程

共14课时 | 0.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号