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

全局CORS配置失效:返回Invalid CORS Request错误

Spring Security CORS配置问题:返回「Invalid CORS Request」错误

在项目中基于Spring Security实现CORS时,OPTIONS预检请求返回「Invalid CORS Request」错误,调试发现自定义的CORS配置未被正确加载,AbstractHandlerMapping的corsInterceptor方法中config为null,自定义配置似乎被覆盖。

实现代码

SecurityFilterChain 配置

@Bean
public SecurityFilterChain oidcFilterChain(final HttpSecurity http) throws Exception {
  return http
      .cors(withDefaults())
      .securityMatcher(new OrRequestMatcher(
          new AntPathRequestMatcher(ApplicationConfig.BASE_PATH + "/**")))
      .csrf(AbstractHttpConfigurer::disable)
      .authorizeHttpRequests(authorize -> authorize
          .anyRequest().authenticated())
      .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
      .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
      .build();
}

CorsConfigurationSource 配置

@Bean
public UrlBasedCorsConfigurationSource corsConfigurationSource() {
  UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

  // 创建CORS配置
  CorsConfiguration config = new CorsConfiguration() {
    {
      setAllowedMethods(List.of(
          HttpMethod.GET.name(),
          HttpMethod.HEAD.name(),
          HttpMethod.POST.name(),
          HttpMethod.PUT.name(),
          HttpMethod.DELETE.name(),
          HttpMethod.OPTIONS.name()));
    }

    // 校验请求Origin是否允许
    @Override
    public String checkOrigin(String requestOrigin) {
      if (requestOrigin == null || requestOrigin.isEmpty()) {
        return null;
      }
      String originToCheck = trimTrailingSlash(requestOrigin);

      try {
        // 获取当前JWT用户
        Jwt jwtUser = SecurityContextUtil.getCurrentUser();

        // 从JWT中获取允许的Origin列表
        List<String> allowedOrigins = jwtUser.getClaimAsStringList(ALLOWED_ORIGINS);

        if (allowedOrigins != null) {
          for (String allowedOrigin : allowedOrigins) {
            if (originToCheck.equalsIgnoreCase(trimTrailingSlash(allowedOrigin))) {
              return requestOrigin;
            }
          }
        }

      } catch (SecurityException e) {
        log.error("SecurityException in CORS Configuration: {}", e.getMessage());
      }
      // 不允许则返回null
      return null;
    }
  };

  // 注册CORS配置到指定路径
  source.registerCorsConfiguration(ApplicationConfig.BASE_PATH + "/**", config);
  return source;
}

SecurityConfig类已添加@EnableWebSecurity和@Configuration注解

测试用例

@Test
@WithJwtTestUser(user = JwtTestUser.PUK_11)
void testPreflightRequest() throws Exception {
  mockMvc.perform(options("/cadastertask/cadasters/" + CADASTER_ID_101_PREMIUM1 + "/regulations/10/tasks")
          .header("Origin", "http://localhost:8081")
          .header("Access-Control-Request-Method", "GET"))
      .andDo(print())
      .andExpect(status().isOk())
      .andExpect(header().string("Access-Control-Allow-Origin", "http://localhost:8081"))
      .andExpect(header().string("Access-Control-Allow-Methods", "GET"))
      .andExpect(header().string("Access-Control-Max-Age", "3600"));
}

响应详情

MockHttpServletRequest:
      HTTP Method = OPTIONS
      Request URI = /cadastertask/cadasters/97190101/regulations/10/tasks
       Parameters = {}
          Headers = [Origin:"http://localhost:8081", Access-Control-Request-Method:"GET"]
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 403
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Allow:"GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE, PATCH"]
     Content type = null
             Body = Invalid CORS request
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: Status expected:<200> but was:<403>
Expected :200
Actual   :403

已尝试的解决方案(均无效)

  • 将corsConfigurationSource()的返回类型改为CorsConfigurationSource接口
  • 通过CorsFilter返回自定义corsConfigurationSource()(此方法可行,但要求必须使用corsConfigurationSource而非过滤器)

求助

请问如何让Spring Security正确加载自定义的CORS配置,解决「Invalid CORS Request」错误?


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:27:09