API网关中OAuth认证结合CORS跨域请求异常排查
OAuth + CORS跨域问题解决方案
问题核心
微服务架构下,Postman携带Bearer token请求API网关可正常访问,但React前端请求时触发CORS异常。原因是:
- 浏览器发送的OPTIONS预检请求不会携带Authorization头,网关的
SecurityContextRepository因拿不到token返回空上下文,触发权限校验失败,进而导致CORS错误 - 前端错误地将
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
相关产品推荐
相关产品推荐

