当前位置:   article > 正文

记一次istio+springcloud gateway 处理跨域问题_gateway globalcors alloworiginpatterns

gateway globalcors alloworiginpatterns

背景:

前端代码要做微前端,我们代码适配了的别人的基座,这个时候所有请求都跨域了


出现的问题:

前端请求跨域,具体显现就不描述了,跨域出现的现象一大把
并且cloud的gateway服务没有配置跨域操作,但是gateway后面的微服务配置了跨域,这样就需要gateway不仅要配置允许跨域,还要屏蔽掉后面微服务的跨域配置(这个后面讲为何)


处理步骤:

Gateway配置跨域

cloud配置跨域,这个简单,网上有很多方法,我记录下对于我来说验证通过的一种方法,直接yaml里面加上如下配置。。

 spring:
    cloud:
      gateway:
        globalcors:
          corsConfigurations:
            '[/**]':
              allowedOriginPatterns: "*"
              allowedMethods: "*"
              allowed-headers: "*"
              allowCredentials: true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

好了,上面解决了配置跨域问题,紧接着出现一个新的问题,刚才说的后端微服务已经配置了跨域,这就导致前端收到请求的时候,access-control-allow-origin: http://y.jd.com,* 或者证书是两个ture。


要么所有后端微服务都去掉跨域配置,要么找到解决方式,将后端服务配置的跨域给替换掉。
其实我是打算所有微服务改造,但是有个大神建议我在gateway拦截器里面搞事情,处理掉response里面的跨域配置。

虽然我内心是拒绝的,但是为了成为一个有追求的coder,我决定尝试一下

Gateway添加过滤器:

其实gateway已经有一个resquest的过滤器了,现在要操作response,尝试各种方式,最终方案如下:

import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

import static org.springframework.http.HttpHeaders.*;


@Component
public class ResponseFilter implements GlobalFilter, Ordered, InitializingBean {

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {

                    try {
                        HttpHeaders headers = originalResponse.getHeaders();

                        String requestUrl = exchange.getRequest().getURI().getPath();
                        List<String> origin = exchange.getRequest().getHeaders().get(ORIGIN);

                        if(origin!=null && origin.size()>0){

                            List<String> origins = new ArrayList<>();
                            origins.add(origin.get(0));
                            //Access-Control-Allow-Origin回填,覆盖
                            headers.put(ACCESS_CONTROL_ALLOW_ORIGIN,origins);
                        }

						//Access-Control-Allow-Credentials回填,覆盖
                        List<String> credentials = new ArrayList<>();
                        credentials.add("true");
                        headers.put(ACCESS_CONTROL_ALLOW_CREDENTIALS, credentials);


                    } catch (Exception e){
                        logger.error("++++++++++++++++++++++++=log headers error", e);
                    }

                return super.writeWith(body);
            }
        };

		//这里别忘了build方法的response方法回填
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public void afterPropertiesSet() throws Exception {

        logger.info("ResponseBodyFilter: [{}]");
    }

    @Override
    public int getOrder() {
    	//response的fileter一定要小于-1,具体原因忘了。
        return -2;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

这样就覆盖掉了gateway后面微服务的跨域配置。瞬间感觉自己萌萌哒!


本来以为事情就结束了,换了一个环境部署以后,发现不生效。依然跨域,我真是fffffffffffuck。

istio配置rbac策略,允许http请求类型

在排查这个问题之前,发现options请求是403,post是跨域,我就按照跨域问题排查:
尝试修改我的gateway配置,以为是gateway的错误,改了好多版本都不生效
然后打印日志,发现都没有进入gateway,我才想着去上游看看

没办法,从头开始定位问题,从网管开始,发现网管日志报错,重点注意报错 rbac_access_denied_matched_policy[none]

[2022-08-03T14:23:04.131Z] "OPTIONS /gw/usercenter/sys/query/user HTTP/1.1" 403 - rbac_access_denied_matched_policy[none] - "-" 0 19 0 - "ip " "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" "ba2a6902-6d98-9999-af12-85c3394e25bc" "mlops-test.jd.com" "-" - - ip2:8080 ip3:43921 - -
  • 1

根据ip找了一下pod和svc,发现是istio网管 cluster-local-gateway的ip,也就是还没有我的gateway服务就被拦截,,
面向百度编程嘛,查查查,最后发现是istio的AuthorizationPolicy配置问题
在这里插入图片描述
添加上,瞬间就好了。

配一张简单手绘图:
在这里插入图片描述

总结

1、OPTIONS请求失败,就会导致post请求报错跨域。
2、GW是个好东西,又是个经常扯我们蛋的工具,像上面的问题,如果没有GW,我就没有这些问题了。但是它有给我很大方便,例如认证,我只需要在GW里面做,后面服务就不用管了,当然认证被破解导致后面服务的危险是认证的问题,和GW无关
3、碰到问题,理清楚思路,从入口开始往下一步一步排查,例如istio的配置,我找了一圈,没有找到原因,才想着回头看istio网管日志的,如果早点看,可能早就解决了。

参考文档:
https://blog.csdn.net/tanjunchen/article/details/123303084

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/181753
推荐阅读
相关标签
  

闽ICP备14008679号