Gateway(拦截器/路由)入门

目录

  • 1、概述
  • 2、实现
  • 3、网关模块
    • 3.1 AbstractGatewayFilterFactory类
    • 3.2 AbstractGatewayFilterFactory和 GlobalFilter区别
  • 4、服务模块
  • 5、服务之间请求传递请求头
  • 6、 代码结构优化

1、概述

微服务框架中网关提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流等。网关作为整个系统的访问入口,我们希望外部请求系统服务都需要通过网关访问,禁止通过ip端口直接访问,特别是一些重要的内部服务(外部无法直接访问的服务)
我们要在项目中实现一个拦截器,需要继承两个类:GlobalFilter, Ordered

GlobalFilter:全局过滤拦截器,在gateway中已经有部分实现

Ordered:拦截器的顺序

于是一个简单的拦截器就有了

2、实现

在网关服务添加全局过滤器,拦截请求并将内部密钥设置到请求头中,这个密钥的规则可以选择合适的算法,我这里用的是字符串。
在内部服务实现Filter 接口,拦截接收到的请求,对密钥的合法性做校验,对合法请求放行并拒绝无效请求。
在这里插入图片描述

3、网关模块

添加全局过滤器拦截处理,将密钥放入请求头中,键名为gatewayKey

/**
 * 全局网关
 */
@Component
public class GatewayFilter implements GlobalFilter , Ordered{
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        PathContainer pathContainer = request.getPath().pathWithinApplication();
        // 添加gatewayKey,防止下游接口直接被访问
        ServerHttpRequest.Builder mutate = request.mutate();
        mutate.header("gatewayKey", "key");
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }
    @Override
    public int getOrder() {
        return 0;
    }
}

ServerWebExchange是Spring框架中的一个接口,用于表示HTTP请求和响应的上下文。它包含了请求和响应的所有信息,例如请求方法、请求头、请求体、响应状态码、响应头、响应体等。通过ServerWebExchange,可以对请求和响应进行操作和处理。

3.1 AbstractGatewayFilterFactory类

AbstractGatewayFilterFactory类中主要包含两个方法:createFilter()和apply()。
createFilter()方法:
该方法用于创建并返回一个GatewayFilter对象。在创建GatewayFilter对象时,可以传入一些配置参数,以定制化过滤器的行为。例如,可以在createFilter()方法中添加自定义的过滤逻辑,并将其封装到一个GatewayFilter对象中,然后将其返回。
示例代码:

java
public abstract GatewayFilter createFilter(Object... args) throws Exception;

apply()方法:
该方法用于将创建好的GatewayFilter对象应用到请求上。在apply()方法中,会接收一个ClientHttpRequestInterceptor对象作为参数,然后将其应用到请求上。这样,在请求被路由到目标服务之前或之后,就会先执行ClientHttpRequestInterceptor中定义的操作。
示例代码:

java
public abstract ClientHttpRequestInterceptor apply(Object... args);

通过实现AbstractGatewayFilterFactory类中的这两个方法,可以创建自定义的GatewayFilter,并将其应用到Spring Cloud Gateway中,以对请求和响应进行拦截和处理。

3.2 AbstractGatewayFilterFactory和 GlobalFilter区别

AbstractGatewayFilterFactoryGlobalFilter在Spring Cloud Gateway中都用于实现过滤功能,但它们之间存在一些区别。

作用范围:
GlobalFilter是一个全局过滤器,会应用于所有的路由请求。
AbstractGatewayFilterFactory是用于创建自定义GatewayFilter的抽象类,它封装了一些常见的过滤器配置逻辑,如添加参数、修改请求头等。
实现方式:
GlobalFilter通过实现GlobalFilter接口来在请求被路由到目标服务之前或之后执行一些操作,例如修改请求或响应,记录日志,添加头部信息等。它是全局性的,对所有的路由都起作用,无需为每个路由单独配置。
继承AbstractGatewayFilterFactory类并实现其中的方法可以创建自定义的GatewayFilter。这种方式提供了一种便捷的方式来创建自定义的GatewayFilter,封装了一些常见的过滤器配置逻辑。
总结来说,GlobalFilter是一个全局过滤器,应用于所有的路由请求;而AbstractGatewayFilterFactory是用于创建自定义GatewayFilter的抽象类,它封装了一些常见的过滤器配置逻辑。

4、服务模块

实现Filter接口,拦截所有请求,对所有请求的合法性做校验

      /**
 * 请求拦截,避免服务绕过接口被直接访问
 */
@Component
@WebFilter(filterName = "BaseFilter",urlPatterns = {"/user/**"})
public class BaseFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init filter");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("进入过滤器========");
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String gateway = request.getHeader("gatewayKey");
        if(gateway == null || gateway.equals("") || !gateway.equals("key")){
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    @Override
    public void destroy() {
        System.out.println("destroy filter");
    }
 
}

5、服务之间请求传递请求头

实现RequestInterceptor接口,将请求放入请求头中,往下传递密钥

@Configuration
public class FeignConfiguration implements RequestInterceptor {
 
    @Override
    public void apply(RequestTemplate template) {
        ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取request请求头信息,传递给下一层
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String values = request.getHeader(name);
                template.header(name, values);
            }
        }
        // 独立设置参数
        template.header("token","tokenKey");
    }
}

以上就是通过密钥校验的方式避免各个服务被直接访问的基本实现了。

6、 代码结构优化

上面的实现需要在每个微服务中实现,对于这部分重复的代码,可以抽象提取到公用服务模块,其他服务按需引入,是否开启网关拦截可通过注解控制。

网关拦截注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({GatewayFilter.class})
@Inherited
public @interface EnableGatewayFilter {
 
}
public class GatewayFilter implements Filter {
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        System.out.println("init gateway filter");
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String gateway = request.getHeader(GatewayFilterConstant.FILTER_KEY_NAME);
        if(gateway == null || gateway.equals("") || !gateway.equals(GatewayFilterConstant.FILTER_KEY_SECRET)){
            System.out.println("======无权访问=======");
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    @Override
    public void destroy() {
        Filter.super.destroy();
        System.out.println("destroy gateway filter");
    }
}

密钥传递注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({CommunicationInterceptor.class})
@Inherited
public @interface EnableInnerCommunication {
}
public class CommunicationInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // 独立设置参数
        template.header(GatewayFilterConstant.FILTER_KEY_NAME,GatewayFilterConstant.FILTER_KEY_SECRET);
    }
}
 组合注解(网关了解+密钥传递)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@EnableInnerCommunication
@EnableGatewayFilter
public @interface EnableGatewayCommunication {
}
实际使用
@SpringBootApplication
@EnableDiscoveryClient
@EnableGatewayFilter
public class ServiceBasicApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceBasicApplication.class, args);
        System.out.println("=========启动成功========");
    }
}

这样就可以通过注解的方式灵活的设置服务是否必须通过网关访问。

思考总结
上述的方案在保障密钥安全的情况下,你的底层内部服务是不会被直接访问的

你也可以设置一定的加解密规则(MD5+时效校验,让密钥具有时效性),保障你的服务安全。

另外,可以对于内部服务,可以设置一定的URL规则,例如:/private/xxxService,网关统一拦截该/private/**类请求,这样外部在尝试访问内部服务的时候在网关就会被过滤掉

上述的方案是避免你的内部服务IP在不慎暴露的时候(这个时候别人就能尝试请求的内部服务了),所以我们在这些底层服务添加了一层拦截,来鉴权访问者是否有权访问。

这种方案要妥善保管服务间通信的密钥,设置合适的加密规则和时效性。

后端专属技术群
我建了一个后端专属技术群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!
文明发言,以交流技术、职位内推、行业探讨为主

图片

关注公众号,拉你进群

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/204436.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云效一键部署前后端

静态站点到OSS 阿里云-云效&#xff0c;阿里云企业级一站式 DevOps&#xff0c;可以免费使用&#xff08;会限制人数、流水线数量等&#xff0c;个人项目够用了&#xff09;。相关文章 CI 持续集成 - 阿里云云效 OSS 是对象存储的意思&#xff0c;一般一个项目对应一个 Bucke…

YOLOv8优化策略:检测头结构全新创新篇 | RT-DETR检测头助力,即插即用

🚀🚀🚀本文改进:RT-DETR检测头助力YOLOv8检测,保持v8轻量级的同时提升检测精度 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1.RT-DETR介绍 论文: https://arxiv.org/pdf/2304.08069.pdf 摘要:…

使用webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题

在我们使用 Selenium 进行 UI 自动化测试时&#xff0c;常常会因为浏览器驱动与浏览器版本不匹配&#xff0c;而导致自动化测试无法执行&#xff0c;需要手动去下载对应的驱动版本&#xff0c;并替换原有的驱动&#xff0c;可能还会遇到跨操作系统进行测试的时候&#xff0c;以…

轨道电流检测IC——FP137/FP137A,适用蓄电池充电器、SPS(适配器)、高侧导轨电流检测器

目录 一、 FP137概述 二、 FP137特点 三、 FP137应用 近年来&#xff0c;随着电子设备的普及与发展&#xff0c;蓄电池充电器、SPS(适配器)、高侧导轨电流检测器等电源产品的需求量不断增加。 货运列车、高铁、地铁以及轨道交通等交通工具&#xff0c;都离不开轨道电流检测…

数据结构与算法复习笔记

1.数据结构基本概念 数据结构: 它是研究计算机数据间关系&#xff0c;包括数据的逻辑结构和存储结构及其操作。 数据&#xff08;Data&#xff09;&#xff1a;数据即信息的载体&#xff0c;是能够输入到计算机中并且能被计算机识别、存储和处理的符号总称。 数据元素&#xf…

python+pytest接口自动化(5)-requests发送post请求

简介 在HTTP协议中&#xff0c;与get请求把请求参数直接放在url中不同&#xff0c;post请求的请求数据需通过消息主体(request body)中传递。 且协议中并没有规定post请求的请求数据必须使用什么样的编码方式&#xff0c;所以其请求数据可以有不同的编码方式&#xff0c;服务…

watch监听中重复触发如何解决?

在实际开发工程中通过获取后端数据监听判断数组中长度是否大于0从而调用其他的方法&#xff0c;但是如果data域中的数据出现变化的话&#xff0c;就会导致监听中的方法重复调用&#xff0c;导致一些不必要的bug&#xff0c;例如&#xff1a; 原理&#xff1a; watch监听的数据…

在java java.util.Date 已知逝去时间怎么求年月日 数学计算不用其他方法

在Java中&#xff0c;使用java.util.Date类已知逝去时间求年月日的方法如下&#xff1a; 首先&#xff0c;获取当前时间和逝去时间之间的毫秒数差值&#xff0c;可以使用Date类的getTime()方法获得时间戳。 将毫秒数转换为秒数&#xff0c;并计算出总共的天数。 根据总共的天…

【刷题笔记】两数之和II_二分法||二分查找||边界||符合思维方式

两数之和II_二分法||二分查找 1 题目描述 https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/ 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设…

天眼销:超有用的企业获客工具

天眼销是资深数据团队开发的一个客户资源查询平台&#xff0c;可以通过多重筛选&#xff1a;企业名称/信用代码&#xff0c;所在地区&#xff0c;行业&#xff0c;注册资本&#xff0c;年限&#xff0c;是否在营/有电话/邮箱等。 天眼销和某查查有什么区别&#xff1f; 天*查/…

鸿蒙(HarmonyOS)应用开发——应用程序入口UIAbility

概述 UIAbility是一种包含用户界面的应用组件&#xff0c;主要用于和用户进行交互 UIAbility是系统调度的单元&#xff0c;为应用提供窗口在其中绘制界面 应用程序的几种交互界面形式 点击桌面图标进入应用 一个应用拉起另一个应用 最近任务列表切回应用 每一个UI Abili…

含压缩空气储能的零排放综合能源系统优化调度程序代码!

本程序参考SCI期刊论文《Optimal dispatch of zero-carbon-emission micro Energy Internet integrated with non-supplementary fired compressed air energy storage system》&#xff0c;程序中有详细的热网模型&#xff0c;温度控制模块&#xff0c;压缩机模块&#xff0c;…

二、shell编程快速入门

目录 1、入门示例 2、解释器 3、shell脚本执行方式 3.1 方式一&#xff1a;sh执行脚本 3.2 方式二&#xff1a;工作目录执行 3.3 方式三&#xff1a;绝对路径执行 ​​​​​​​4、shell的数据类型 4.1 字符串 4.2 整数型 1、入门示例 以下所有操作都在/export/shel…

Web应用渗透测试完全指南(二)

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

【开源】基于JAVA的天然气工程运维系统

项目编号&#xff1a; S 022 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S022&#xff0c;文末获取源码。} 项目编号&#xff1a;S022&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统角色分类2.2 核心功能2.2.1 流程…

lxd提权

lxd/lxc提权 漏洞介绍 lxd是一个root进程&#xff0c;它可以负责执行任意用户的lxd&#xff0c;unix套接字写入访问操作。而且在一些情况下&#xff0c;lxd不会调用它的用户权限进行检查和匹配 原理可以理解为用用户创建一个容器&#xff0c;再用容器挂载宿主机磁盘&#xf…

数据库安全运维系统厂家在深圳的有哪些?咨询电话多少?

IT小伙伴都知道&#xff0c;数据库安全运维至关重要&#xff0c;因为随着信息技术的不断发展&#xff0c;数据库已经成为企业存储、管理和处理数据的关键平台&#xff0c;数据库承载着企业不少数据资产。因此使用数据库安全运维系统是必要的。那你知道数据库安全运维系统厂家在…

Vue3 刷新后,pinia存储的数据丢失怎么解决

这个问题有两种解决办法&#xff1a; 一是使用pinia的持久化存储一是使用vue的依赖注入 刷新后&#xff0c;通过pinia存储的vue store数据丢失&#xff0c;实际上是因为Vue原组件卸载、新组件重新挂载导致的&#xff0c;vue store是挂载在组件上的&#xff0c;当刷新导致组件…

数据库的多表查询(MYSQL)表表联立

根据以上三张表格&#xff0c;对三张表格进行不同的联立&#xff0c;查询并显示符合条件的内容。 1. 查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数。 mysql> SELECT d.deptno AS 部门编号, d.dname as 部门名称, d.loc as 部门位置, COUNT(e.emp…

uniapp2023年微信小程序头像+昵称分别获取

1、DOM <view class"m-user"><view class"user-info"><!--头像 GO--><button class"avatar avatar-wrapper" open-type"chooseAvatar" chooseavatar"onChooseAvatar"slot"right"><im…