先说问题怎么解决的:
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;
}