解决跨域请求,NG返回403(403并不一定是NG问题)
作者:zero
这篇文章主要介绍了解决跨域请求,NG返回403(403并不一定是NG问题),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
先说问题怎么解决的
1.ng返回403的情况也就那么几种,百度一下都能找到,但是ng返回403不一定是ng的问题。
2.最终发现是在网关跨域配置中,没有加上请求方的域名。
3.想探索的可以看看文章
背景
和合作方对接,我们这边的app开发完放在合作方的服务器上,再通过NG,请求我这边的后台。
NG配置跨域等信息后(这个很容易找,百度随便都能找到),发现测试环境一切正常,但是到了生产,NG一直返回403。
请求都没通过,网关zuul没有日志。双方开始排查NG,百度了无数次。
最后都配置与测试环境一直,但是生产一直不通。
返回403,加上zuul没日志,一直定位在NG跨域的问题上。
解决
最后发现是zuul项目的问题,SpringBoot跨域问题。
尝试排查是否zuul的问题,对比了测试环境和生产的。
测试环境zuul的跨域配置CorsConfiguration类属性allowedOrigins赋值了个*,生产是针对地址进行配置的。
其实就是SpringBoot的跨域配置,源码CorsConfiguration的allowedOrigins属性没有加上第三方的域名地址。
导致直接被拒绝了。加上合作方地址,问题解决。
源码解析
在配置跨域问题时,我们需要对CorsConfiguration属性赋值
//对CorsConfiguration属性赋值 private CorsConfiguration corsConfig(Map.Entry<String, JawsCorsConfig> entry) { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedOrigins(Splitter.on(",").splitToList(entry.getValue().getAllowedOrigins())); corsConfiguration.setAllowedHeaders(Splitter.on(",").splitToList(entry.getValue().getAllowedHeaders())); corsConfiguration.setAllowedMethods(Splitter.on(",").splitToList(entry.getValue().getAllowedMethods())); corsConfiguration.setAllowCredentials(entry.getValue().getAllowCredentials()); corsConfiguration.setMaxAge(entry.getValue().getMaxAge()); return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); for (Map.Entry<String, JawsCorsConfig> entry : jawsZuulProperites.getCors().entrySet()) { source.registerCorsConfiguration(entry.getValue().getUrls(), corsConfig(entry)); } return new CorsFilter(source); }
源码中 org.springframework.web.cors.DefaultCorsProcessor#handleInternal 方法
protected boolean handleInternal(ServerHttpRequest request, ServerHttpResponse response, CorsConfiguration config, boolean preFlightRequest) throws IOException { String requestOrigin = request.getHeaders().getOrigin(); String allowOrigin = checkOrigin(config, requestOrigin); HttpMethod requestMethod = getMethodToUse(request, preFlightRequest); List<HttpMethod> allowMethods = checkMethods(config, requestMethod); List<String> requestHeaders = getHeadersToUse(request, preFlightRequest); List<String> allowHeaders = checkHeaders(config, requestHeaders); if (allowOrigin == null || allowMethods == null || (preFlightRequest && allowHeaders == null)) { rejectRequest(response); return false; } HttpHeaders responseHeaders = response.getHeaders(); responseHeaders.setAccessControlAllowOrigin(allowOrigin); responseHeaders.add(HttpHeaders.VARY, HttpHeaders.ORIGIN); if (preFlightRequest) { responseHeaders.setAccessControlAllowMethods(allowMethods); } if (preFlightRequest && !allowHeaders.isEmpty()) { responseHeaders.setAccessControlAllowHeaders(allowHeaders); } if (!CollectionUtils.isEmpty(config.getExposedHeaders())) { responseHeaders.setAccessControlExposeHeaders(config.getExposedHeaders()); } if (Boolean.TRUE.equals(config.getAllowCredentials())) { responseHeaders.setAccessControlAllowCredentials(true); } if (preFlightRequest && config.getMaxAge() != null) { responseHeaders.setAccessControlMaxAge(config.getMaxAge()); } response.flush(); return true; }
进入checkOrigin(config, requestOrigin);校验请求来源
public static final String ALL = "*"; /** * Check the origin of the request against the configured allowed origins. * @param requestOrigin the origin to check * @return the origin to use for the response, or {@code null} which * means the request origin is not allowed */ public String checkOrigin(String requestOrigin) { if (!StringUtils.hasText(requestOrigin)) { return null; } if (ObjectUtils.isEmpty(this.allowedOrigins)) { return null; } if (this.allowedOrigins.contains(ALL)) { if (this.allowCredentials != Boolean.TRUE) { return ALL; } else { return requestOrigin; } } //遍历我们赋值的allowedOrigins,判断请求来源是否包含,包含则返回 for (String allowedOrigin : this.allowedOrigins) { if (requestOrigin.equalsIgnoreCase(allowedOrigin)) { return requestOrigin; } } return null; }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。