You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中如何在整个Rest Controller上禁用JwtFilter?

问题描述

我在Spring Boot项目中实现了基于JWT的安全机制,创建了两个过滤器并加入过滤器链,分别用于生成JWT令牌和验证用户是否持有令牌。由于是测试项目,端点不多,我重写了验证令牌的过滤器的shouldNotFilter方法,使其在注册、登录等请求上不生效,代码如下:

@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
   if(request.getRequestURI().startsWith("/login")
           || request.getRequestURI().startsWith("/api/users/registration"))
       return true;
   return false;
}

但目前只有这两个端点,若需要在整个Controller上禁用该过滤器,是否有可用的注解实现?还是需要删除该重写方法,改用.antMatchers(端点列表).permitAll()?


补充代码

AuthController代码

@RestController
@RequestMapping("/api/users")
public class AuthController {
    private final UserFacadeService userFacadeService;

    @Autowired
    public AuthController(UserFacadeService userFacadeService) {
        this.userFacadeService = userFacadeService;
    }

    @PostMapping("/registration")
    public ResponseEntity<Object> signUp(@RequestBody @Valid UserDTO userDTO){
        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(LocalDateTime.now()
                        + " user created: "
                        + this.userFacadeService.saveUser(userDTO));
    }
}

SecurityConfig代码

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    private final UserService userService;
    @Autowired
    @Lazy
    private  LoginFilter loginFilter;

    private final JwtFilter jwtFilter;
    private final PasswordEncoder passwordEncoder;
    private final ExceptionHandlerFilter exFilter;

    @Autowired
    public SecurityConfig(UserService userService,
                          JwtFilter jwtFilter,
                          PasswordEncoder passwordEncoder,
                          ExceptionHandlerFilter exFilter) {
        this.userService = userService;
        this.jwtFilter = jwtFilter;
        this.passwordEncoder = passwordEncoder;
        this.exFilter = exFilter;
    }

    @Bean
    public AuthenticationManager authenticationManager(){
        DaoAuthenticationProvider dao = new DaoAuthenticationProvider();
        dao.setUserDetailsService(userService);
        dao.setPasswordEncoder(passwordEncoder);
        return new ProviderManager(dao);
    }

    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests((auth)->auth
                        .expressionHandler(webExpressionHandler())
                        .antMatchers(AUTH_WHITELIST)
                        .permitAll()
                        .antMatchers("/api/users/registration")
                        .permitAll()
                        .anyRequest()
                        .authenticated()
                        .and()
                        .addFilterBefore(exFilter, ChannelProcessingFilter.class)
                        .addFilterAt(loginFilter, BasicAuthenticationFilter.class)
                        .addFilterAt(jwtFilter,BasicAuthenticationFilter.class)
                );

        return http.build();
    }

    // 实现角色层级需要定义SecurityExpressionHandler并加入过滤器链
    private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler
                = new DefaultWebSecurityExpressionHandler();
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
        return defaultWebSecurityExpressionHandler;
    }

    // 定义角色层级,高权限角色可访问低权限角色的所有API
    @Bean
    public RoleHierarchyImpl roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("OPERATOR > CUSTOMER");
        return roleHierarchy;
    }
}

解决方案

方案一:注解方式禁用过滤器(@WebFilter)

如果你的JWT过滤器继承自OncePerRequestFilter,可以直接给过滤器类添加@WebFilter注解,通过excludeUrlPatterns指定要排除的路径(即整个Controller的路径):

@WebFilter(urlPatterns = "/*", excludeUrlPatterns = "/api/users/**")
public class JwtFilter extends OncePerRequestFilter {
    // 你的过滤器逻辑
}

同时需要在项目启动类上添加@ServletComponentScan,让Spring扫描到这个注解配置的过滤器。注意这种方式和Spring Security过滤器链的配置可能存在优先级冲突,需要确保规则一致。

方案二:统一在SecurityConfig中配置(推荐)

直接删除过滤器中重写的shouldNotFilter方法,在filterChain里通过antMatchers统一配置放行路径,这样更符合Spring Security的集中配置风格,后续扩展端点也更方便:

.authorizeRequests((auth)->auth
        .expressionHandler(webExpressionHandler())
        .antMatchers(AUTH_WHITELIST, "/api/users/**")
        .permitAll()
        .anyRequest()
        .authenticated()
        // ... 其他配置
)

这样/api/users下的所有端点都会被自动放行,后续新增端点到该Controller时,无需修改过滤器代码,直接继承该路径规则即可。

方案三:方法级权限注解(细粒度控制)

如果需要针对单个方法放行,可以利用已开启的@EnableGlobalMethodSecurity(prePostEnabled = true),给Controller方法添加@PreAuthorize("permitAll()"):

@PostMapping("/registration")
@PreAuthorize("permitAll()")
public ResponseEntity<Object> signUp(@RequestBody @Valid UserDTO userDTO){
    // 方法逻辑
}

不过这种方式是权限放行,过滤器仍会执行,只是权限校验直接通过。如果需要真正禁用过滤器执行,还是前两种方案更直接。


内容的提问来源于stack exchange,提问作者Rezel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 18:45:41