Spring Cloud Gateway之路由转发

大家好,愉快的周末时光又到了!今天,我想和大家分享一个关于如何在项目中高效利用Spring Cloud Gateway来增强系统安全性的实践案例。

背景

在我们的项目中,前端需要直接对接多个未经鉴权的三方接口,这无疑给系统安全带来了潜在的风险。为了提升系统安全性,我们决定将这些三方交互交由后端统一处理,并在转发过程中对请求数据进行加密。面对超过50个接口的需求,我们选择了快速且安全的转发策略。

我们先了解下Spring Cloud Gateway 都有哪些功能。

1. 路由转发:

  • Gateway能够根据请求的URL路径、参数或头部等条件,智能地将请求转发至后端的多个服务。此外,它还支持动态路由配置,便于灵活调整路由规则。

2. 过滤器机制:

  • 提供了丰富的过滤器链,允许我们在请求处理过程中进行多种操作,如请求验证、数据加密、日志记录、请求转发或重试等,极大地增强了请求的灵活性和安全性。

3. 集成断路器:

  • 可以无缝集成如Netflix Hystrix这样的断路器框架,为微服务网关提供强大的容错能力,确保在高并发或服务故障时系统的稳定性和可用性。

4. 服务发现集成:

  • Gateway能够轻松与服务注册中心(Eureka、Consul、Zookeeper等)集成,实现服务的动态发现和路由,降低服务间的耦合度,提升系统的可扩展性和可维护性。

5. 协议转换:

  • 支持将HTTP请求转换为其他协议(如WebSocket),满足多样化的通信需求,扩展了系统的通信能力。

6. 请求限流:

  • 通过配置限流规则,有效控制请求的流量,防止恶意攻击或突发流量对系统造成冲击,保护系统资源的安全和稳定。

针对我们的需求,我们利用Spring Cloud Gateway的路由转发和过滤器功能,实现了对所有三方接口的集中管理和安全加固。通过配置路由规则,我们将前端请求转发至后端服务,并在转发过程中通过过滤器对请求数据进行加密处理,有效提升了数据传输的安全性。

希望这个实践案例能给大家带来一些启发和帮助,让我们在享受技术带来的便利的同时,也能不断提升系统的安全性和稳定性。祝大家周末愉快!

进入正题:

application.yml配置:


server:
  port: 8081

spring:
  cloud:
    gateway:
      routes: # 网关路由配置
        - id: yeyYngXuan_service # 路由id,只要唯一即可
          uri: http://localhost:8080 # (三方)路由的目标地址
          predicates: # 路由断言,判断请求是否符合路由规则的条件
            - Path=/api/**
          filters:
            - StripPrefix=1 #转发时去调/api目录
            - name: EncryptRequestParamsFilter #过滤器
#          filters:
#            - name: RewritePath
#              args:
#                regexp: ^/api/(?<remaining>.*) #通过正则将/api/替换成/
#                replacement: /${remaining}
#            - name: EncryptRequestParamsFilter

这里filters给大家提供了2种配置,一种直接从URL中删除指定数量的路径段,另一种是通过正则表达式匹配并将修改路径。

例如三方接口路径是:http://localhost:8080/yeYingXuan_test,那么前端请求我们时候请求http://localhost:8081/api/yeYingXuan_test就会被转发到http://localhost:8080/yeYingXuan_test上,并起转发前会去过滤器进行数据加密。

简单讲解一下配置:

id:路由id,唯一即可

uri:配置要跳转的三方系统的域名,我这里是转发到另一个项目。

predicates:将请求路径带/api/的所有请求都转发到uri配置到地址上。

filters.StripPrefix=1:#因为有一些是要转到三方的,有些不需要,所以前端请求的时候加一层路径/api用来区分是否转发,但是三方接口其实是没有这层路径的,所以实际转发的时候要把这一层路径给去掉。

filters.name:要执行的过滤器的名称。

过滤器代码:

package com.syl.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

@Component
public class EncryptRequestParamsFilter extends AbstractGatewayFilterFactory<EncryptRequestParamsFilter.Config> {

    public EncryptRequestParamsFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            if ("POST".equalsIgnoreCase(request.getMethodValue()) && MediaType.APPLICATION_JSON.equals(request.getHeaders().getContentType())) {
                return DataBufferUtils.join(request.getBody())
                        .flatMap(dataBuffer -> {
                            byte[] bytes = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(bytes);
                            DataBufferUtils.release(dataBuffer);
                            String body = new String(bytes, StandardCharsets.UTF_8);

                            try {

                                String encryptedBody = encrypt(body);

                                ServerHttpRequestDecorator modifiedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                                    @Override
                                    public Flux<DataBuffer> getBody() {
                                        byte[] bytes = encryptedBody.getBytes(StandardCharsets.UTF_8);
                                        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                                        return Flux.just(buffer);
                                    }

                                    @Override
                                    public HttpHeaders getHeaders() {
                                        HttpHeaders headers = new HttpHeaders();
                                        headers.putAll(super.getHeaders());
                                        headers.setContentLength(encryptedBody.getBytes(StandardCharsets.UTF_8).length);
                                        headers.setContentType(MediaType.APPLICATION_JSON);
                                        return headers;
                                    }
                                };

                                ServerWebExchange modifiedExchange = exchange.mutate().request(modifiedRequest).build();
                                return chain.filter(modifiedExchange);
                            } catch (Exception e) {
                                return Mono.error(new RuntimeException("过滤器处理过程发生错误", e));
                            }
                        });
            }
            return chain.filter(exchange);
        };
    }

    private String encrypt(String value) {
        try {
            // TODO 选择自己的加密方式
        } catch (Exception e) {
            throw new RuntimeException("加密时发生异常", e);
        }
    }

    public static class Config {
    }
}

我这里只针对post的请求做了处理,加密方式大家可以自行选择。

三方接口代码:

@PostMapping("yeYingXuan_test")
    public Object test2(@RequestBody String body){

        log.info("请求报文:{}", body);
        // TODO 解密后进行逻辑处理。

        return "{\"msg\":\"成功\",\"code\":0,\"data\":0}";
    }

我们gateawy的端口是8081,三方的端口是8080,接下来我们请求8081端口,如果能收到返回{\"msg\":\"成功\",\"code\":0,\"data\":0}就代表我们已经成功了,接下来我们验证一下。

验证结果正如预期般圆满,一个精心配置的Spring Cloud Gateway解决方案,便轻松实现了对数十个接口的高效路由管理,这一成果显著超越了逐个编写透传代码的传统方法,不仅简化了开发流程,还大幅提升了开发效率。

通过利用Gateway的路由转发与过滤器机制,我们得以集中处理所有涉及的三方接口请求,同时确保在转发过程中对敏感数据进行加密,从而有效提升了系统的安全性和数据保护能力。这种集中式的路由管理策略,大大减少了代码冗余。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值