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

Spring Boot部分端点OAuth2、部分API Key认证的异常排查

问题解决:添加API Key过滤器后JWT认证端点无需令牌即可访问

问题背景

需要实现三类端点的认证规则:

  • /secured/**:需Google OAuth2 JWT令牌访问
  • /secured-with-api-key/**:需API Key(含timestamp、signature头)访问
  • /non-secured/**:允许任意访问

未添加ApiKeyAuthFilter时功能正常,但添加后,/secured-with-api-key/**和/non-secured/**表现符合预期,唯独/secured/**无需JWT令牌即可直接访问。

问题原因

在同一个configure(HttpSecurity)方法中多次调用antMatcher()会导致配置冲突:每次调用antMatcher()都会重置当前HttpSecurity的请求匹配规则,后续配置会覆盖前面的规则。同时,oauth2ResourceServer().jwt()的全局配置没有被正确关联到/secured/**的路径规则上,导致JWT认证逻辑未生效。

解决方案

方案1:使用多SecurityFilterChain Bean(推荐Spring Security 5.7+)

将不同路径的安全配置拆分为独立的SecurityFilterChain Bean,每个Bean对应一组路径的认证规则,确保彼此独立生效:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthConfig {

    private static final String API_KEY_HEADER_NAME = "API_KEY";
    private static final String TIMESTAMP_HEADER_NAME = "timestamp";
    private static final String SIGNATURE_HEADER_NAME = "signature";

    @Autowired
    private SimpleAuthenticationManager simpleAuthenticationManager;

    // 开放/non-secured/**路径
    @Bean
    public SecurityFilterChain nonSecuredFilterChain(HttpSecurity http) throws Exception {
        http
            .requestMatchers(matchers -> matchers.antMatchers("/non-secured/**"))
            .authorizeRequests(auth -> auth.anyRequest().permitAll())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .cors().and().csrf().disable();
        return http.build();
    }

    // API Key认证:/secured-with-api-key/**
    @Bean
    public SecurityFilterChain apiKeySecuredFilterChain(HttpSecurity http) throws Exception {
        ApiKeyAuthFilter filter = new ApiKeyAuthFilter(API_KEY_HEADER_NAME, TIMESTAMP_HEADER_NAME, SIGNATURE_HEADER_NAME);
        filter.setAuthenticationManager(simpleAuthenticationManager);

        http
            .requestMatchers(matchers -> matchers.antMatchers("/secured-with-api-key/**"))
            .addFilter(filter)
            .authorizeRequests(auth -> auth.anyRequest().authenticated())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .cors().and().csrf().disable()
            .oauth2ResourceServer().disable(); // 禁用JWT认证,避免干扰
        return http.build();
    }

    // JWT认证:/secured/**
    @Bean
    public SecurityFilterChain jwtSecuredFilterChain(HttpSecurity http) throws Exception {
        http
            .requestMatchers(matchers -> matchers.antMatchers("/secured/**"))
            .authorizeRequests(auth -> auth.anyRequest().fullyAuthenticated())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .cors().and().csrf().disable()
            .oauth2ResourceServer(oauth2 -> oauth2.jwt()); // 启用JWT认证
        return http.build();
    }
}

方案2:兼容旧版本WebSecurityConfigurerAdapter

如果仍需使用WebSecurityConfigurerAdapter,通过and()链式连接不同路径的配置,避免多次调用antMatcher()导致的规则覆盖:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthConfig extends WebSecurityConfigurerAdapter {

    private static final String API_KEY_HEADER_NAME = "API_KEY";
    private static final String TIMESTAMP_HEADER_NAME = "timestamp";
    private static final String SIGNATURE_HEADER_NAME = "signature";

    @Autowired
    private SimpleAuthenticationManager simpleAuthenticationManager;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ApiKeyAuthFilter filter = new ApiKeyAuthFilter(API_KEY_HEADER_NAME, TIMESTAMP_HEADER_NAME, SIGNATURE_HEADER_NAME);
        filter.setAuthenticationManager(simpleAuthenticationManager);

        http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .cors().and().csrf().disable()
            // 配置开放路径
            .authorizeRequests()
                .antMatchers("/non-secured/**").permitAll()
            // 配置API Key认证路径
            .and()
                .antMatcher("/secured-with-api-key/**")
                .addFilter(filter)
                .authorizeRequests()
                .antMatchers("/secured-with-api-key/**").authenticated()
            // 配置JWT认证路径
            .and()
                .antMatcher("/secured/**")
                .authorizeRequests()
                .antMatchers("/secured/**").fullyAuthenticated()
            // 绑定JWT认证逻辑到对应路径
            .and()
                .oauth2ResourceServer().jwt();
    }
}

关键说明

  • 多SecurityFilterChain Bean方式下,Spring Security会根据请求路径自动匹配对应的FilterChain,确保各类认证逻辑互不干扰。
  • API Key配置中需禁用oauth2ResourceServer,防止JWT认证逻辑影响API Key路径;JWT配置中单独启用JWT资源服务器,确保/secured/**路径强制验证JWT令牌。
  • 链式配置方式通过and()分隔不同路径的规则,避免多次重置请求匹配器导致的配置覆盖问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 11:25:57