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

API网关中OAuth认证结合CORS跨域请求异常排查

OAuth + CORS跨域问题解决方案

问题核心

微服务架构下,Postman携带Bearer token请求API网关可正常访问,但React前端请求时触发CORS异常。原因是:

  1. 浏览器发送的OPTIONS预检请求不会携带Authorization头,网关的SecurityContextRepository因拿不到token返回空上下文,触发权限校验失败,进而导致CORS错误
  2. 前端错误地将Access-Control-*这类服务器响应头添加到请求头中,违反跨域规则

前端修复

删除请求中的Access-Control-*请求头(这些是服务器返回给浏览器的响应头,无需前端发送),并清理重复的Authorization配置:

var config = {
  method: 'get',
  url: 'http://localhost:8765/REGISTRATION-SERVICE/test',
  headers: { 
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});

后端(API网关)修复

1. 配置正确的CORS规则

添加CORS配置,允许前端域名、自定义头(如Authorization)、所有请求方法,并支持凭证传递:

@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration corsConfig = new CorsConfiguration();
        // 替换为你的React前端实际域名,如http://localhost:3000
        corsConfig.addAllowedOrigin("http://localhost:3000");
        corsConfig.addAllowedHeader("*");
        corsConfig.addAllowedMethod("*");
        corsConfig.setAllowCredentials(true);
        // 允许Authorization头暴露给前端(可选)
        corsConfig.addExposedHeader(HttpHeaders.AUTHORIZATION);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfig);

        return new CorsWebFilter(source);
    }
}

2. 修改SecurityContextRepository,跳过OPTIONS请求认证

OPTIONS预检请求无需携带Authorization,直接放行,避免触发权限校验:

@Override
public Mono<SecurityContext> load(ServerWebExchange swe) {
    ServerHttpRequest request = swe.getRequest();
    
    // 跳过OPTIONS预检请求的认证流程
    if (HttpMethod.OPTIONS.equals(request.getMethod())) {
        return Mono.empty();
    }

    HttpHeaders headers = request.getHeaders();
    String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);

    if (authHeader != null && authHeader.startsWith("Bearer ")) {
        String authToken = authHeader.substring(7);
        Authentication auth = new UsernamePasswordAuthenticationToken(authToken, authToken);
        return this.authenticationManager.authenticate(auth)
                .map(SecurityContextImpl::new);
    } else {
        return Mono.empty();
    }
}

3. 配置Spring Security允许OPTIONS请求

在安全过滤链中明确允许所有OPTIONS请求无需认证:

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    http
        .authorizeExchange(exchanges -> exchanges
            .pathMatchers(HttpMethod.OPTIONS).permitAll()
            .anyExchange().authenticated()
        )
        .securityContextRepository(yourSecurityContextRepository);
    
    return http.build();
}

关键说明

  • 浏览器自动发起的OPTIONS预检请求不会携带自定义头(如Authorization),后端必须单独处理,不能走正常认证流程
  • 若前端需要传递凭证(如Cookie),Access-Control-Allow-Origin不能设为*,必须指定具体的前端域名
  • Access-Control-*系列头是服务器响应给浏览器的规则,前端不需要在请求中发送

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 22:36:33