• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

完美解决Spring Cloud Gateway跨域配置不生效问题

武飞扬头像
Ellis_li
帮助1

最近使用springcloud gateway时,遇到了一个跨域的问题,开始的时候还觉得是个soeasy的问题,加个跨域配置不就完事了么,可是,百度找了三种跨域配置方式,怎么就是不生效,一个跨域问题搞了将近两天才解决,麻了麻了~

解决方案

yml配置文件

spring:
  application:
    name: gateway
  cloud:
    # gateway 配置
    gateway:
      filter:
        remove-hop-by-hop:
          headers:
            # 以下是去掉网关默认去掉的请求响应头
            - trailer
            - te
            - keep-alive
            - transfer-encoding
            - upgrade
            - proxy-authenticate
            - connection
            - proxy-authorization
            - x-application-context
            # 以下是去掉服务层面定义的跨域
            - access-control-allow-credentials
            - access-control-allow-headers
            - access-control-allow-methods
            - access-control-allow-origin
            - access-control-max-age
            - vary
      globalcors:
        corsConfigurations:
          '[/**]':
            allowCredentials: true
            allowedOrigins: "*"
            allowedHeaders: "*"
            allowedMethods: "*"
            maxAge: 3628800

这就OK了吗?不不不

通过百度搜索,文章里有很多配置跨域的方式,上面的yml配置也好,自己加配置类也好,我亲身实验的效果就是不生效。

网关拦截器的坑

使用gateway网关,有一个重要的点就是想要去进行统一拦截,如登录拦截啊、授权认证啊等等,这些都需要在网关的拦截器里做处理
所以有了下图的自定义拦截器
学新通
拦截器里的return的值需要处理跨域,不然配置文件里的跨域配置就会不生效,前后对比如下:
学新通

代码

最后把我自定义的网关拦截器代码贴一下,没有的逻辑可以自行删除,我就直接贴所有的代码了。


import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {

    private static final String TRACE_ID = "traceId";

    private static final AntPathMatcher matcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        //对请求对象request进行增强
        ServerHttpRequest req = request.mutate().headers(httpHeaders -> {
            //httpHeaders 封装了所有的请求头
            String traceId = UUID.randomUUID().toString(true);
            MDC.put(TRACE_ID, traceId);
            httpHeaders.set(TRACE_ID, traceId);
        }).build();
        //设置增强的request到exchange对象中
        exchange.mutate().request(req);
        String url = request.getURI().getPath();
        log.info("接收到请求:{}", url);
        // 不需要拦截的接口直接放行
        if (needLogin(request.getPath().toString())) {
            log.info("不拦截放行");
            return getVoidMono(exchange, chain);
        }
        // 授权验证
        if (!this.auth(exchange)) {
            return this.responseBody(exchange, 406, "请先登录");
        }
        log.info("认证成功,放行");
        return getVoidMono(exchange, chain);
    }

    private Mono<Void> getVoidMono(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange).then(Mono.defer(() -> {
            exchange.getResponse().getHeaders().entrySet().stream()
                    .filter(kv -> kv.getValue() != null && kv.getValue().size() > 1)
                    .filter(kv -> kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)
                            || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS))
                    .forEach(kv -> kv.setValue(Collections.singletonList(kv.getValue().get(0))));
            return chain.filter(exchange);
        }));
    }

    /**
     * 是否需要登录
     *
     * @param uri 请求URI
     * @return boolean
     */
    public static boolean needLogin(String uri) {
        // test
        List<String> uriList = new ArrayList<>();
        uriList.add("/user/cloud/login");
        uriList.add("/user/token");
        uriList.add("/user/verify");

        for (String pattern : uriList) {
            if (matcher.match(pattern, uri)) {
                // 不需要拦截
                return true;
            }
        }
        return false;
    }

    /**
     * 认证拦截
     */
    private boolean auth(ServerWebExchange exchange) {
        String token = this.getToken(exchange.getRequest());
        log.info("token:{}", token);

        if (StrUtil.isBlank(token)) {
            return false;
        }
        JSONObject userInfo = getUserInfo(token);
        return !ObjectUtil.isNull(userInfo);
    }

    private JSONObject getUserInfo(String token) {
        JSONObject jsonObject;
        String tokenNew = token.substring(7);
        String ss = JWT.decode(tokenNew).getPayload();
        Base64.Decoder decoder = Base64.getDecoder();
        jsonObject = JSON.parseObject(new String(decoder.decode(ss)));
        return jsonObject;
    }

    /**
     * 获取token
     */
    public String getToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst("Authorization");
        if (StrUtil.isBlank(token)) {
            return request.getQueryParams().getFirst("Authorization");
        }
        return token;
    }

    /**
     * 设置响应体
     **/
    public Mono<Void> responseBody(ServerWebExchange exchange, Integer code, String msg) {
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put("code", code);
        hashMap.put("msg", msg);
        String message = JSON.toJSONString(hashMap);
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        return this.responseHeader(exchange).getResponse()
                .writeWith(Flux.just(exchange.getResponse().bufferFactory().wrap(bytes)));
    }

    /**
     * 设置响应体的请求头
     */
    public ServerWebExchange responseHeader(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/json");
        return exchange.mutate().response(response).build();
    }

    @Override
    public int getOrder() {
        return 0;
    }

}

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfikjag
系列文章
更多 icon
同类精品
更多 icon
继续加载