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{@Overridepublic 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());}@Overridepublic 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 {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("init filter");}@Overridepublic 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);}@Overridepublic void destroy() {System.out.println("destroy filter");}}

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

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

@Configuration
public class FeignConfiguration implements RequestInterceptor {@Overridepublic 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 {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);System.out.println("init gateway filter");}@Overridepublic 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);}@Overridepublic 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 {@Overridepublic 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进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!
文明发言,以交流技术、职位内推、行业探讨为主

图片

关注公众号,拉你进群

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每天一点python——day81

#每天一点Python——81 #递归函数&#xff1a; 递归函数&#xff1a; 一个函数在该函数体内调用了该函数本身&#xff0c;这个函数称为递归函数 【释&#xff1a;我自己调用自己的函数】 递归函数的组成部分&#xff1a; 递归调用与递归终止条件。 【一定有一个跳出循环的终止条…

JDK版本降级,如何重新编译打包项目

目前大部分人使用jdk1.8以及更高版本的jdk&#xff0c;在开发过程中也使用了很多jdk1.8的新特性&#xff0c;但或许还存在一些使用jdk低版本的客户&#xff0c;这时如果我们提供的代码涉及必须高版本jdk才能运行的话&#xff0c;那代码就必须降级&#xff0c;客户才能使用&…

【IDEA开发工具的常用设置和快捷键及Debug调试】

&#x1f320;作者&#xff1a;TheMythWS. &#x1f387;座右铭&#xff1a;不走心的努力都是在敷衍自己&#xff0c;让自己所做的选择&#xff0c;熠熠发光。 目录 常用设置篇 【1】进入设置 【2】设置主题 【3】编辑区的字体变大或者变小 【4】鼠标悬浮在代码上有提示…

我的创作纪念日--成为创作者的 第1825天(5年) 啦

醉颜凉 &#xff0c;不知不觉今天已经是你成为创作者的 第1825天&#xff08;5年&#xff09; 啦。 机缘 1、作为一个创作者&#xff0c;我最初成为创作者的初心是出于对技术的热爱和对分享的渴望。我希望通过创作&#xff0c;将自己在实战项目中的经验分享给大家&#xff0c;…

如何写好开发信标题?推荐的营销邮件主题?

打开率高的开发信标题有哪些&#xff1f;怎么写吸引人邮件标题&#xff1f; 开发信标题是您的邮件首次与受众接触的部分&#xff0c;因此&#xff0c;它必须引起他们的兴趣&#xff0c;激发他们打开邮件的欲望。蜂邮EDM将讨论如何写好开发信标题&#xff0c;以及一些成功的开发…

创业者如何在居家办公和固定办公场地办公中权衡利弊,选择合适的

创业者如何选择办公方式&#xff0c;可能要根据自己的创业项目、团队规模、资金情况、行业特点等多方面因素来考虑。一般来说&#xff0c;居家办公和固定办公场地各有优缺点&#xff0c;没有绝对的好坏&#xff0c;只有适合不适合。我为大家总结了一些相关的信息&#xff0c;希…

Elk+Filebeat+Kafka实现日志收集

ElkFilebeatKafka实现日志收集(本机nginx) 部署Zookeeper 1.实验组件 #准备3台服务器做Zookeeper集群 20.0.0.10 20.0.0.20 20.0.0.30 2.安装前准备 #关闭防火墙 systemctl stop firewalld systemctl disable firewalld setenforce 0#安装JDK yum install -y java-1.8.0-o…

C++ 学习笔记——C++纯虚函数和抽象类

C纯虚函数 什么是纯虚函数 1&#xff0c;纯虚函数只有函数名、参数、返回值类型。 2&#xff0c;纯虚函数的定义是在函数句首使用 virtual 关键字修饰&#xff0c;并且在句末增加 “ 0”。 virtual void funtion() 0;3&#xff0c;纯虚函数只有声明&#xff0c;基类可以存…

juniper EX系列交换机 CLI命令行操作模式

JUNOS有两种模式&#xff1a;操作模式和配置模式。 1&#xff0c;操作模式 监控和排错 软件&#xff0c;网络连接、路由器硬件。 2&#xff0c;配置模式 testlab2> 配置路由器包括&#xff1a;interface、路由信息、路由协议、用户访问、系统硬件参数。 testlab2> …

Android笔记(十六):前台服务

设置服务为前台服务。前台服务会在状态栏显示一个通知。通知界面与服务进行关联。 一、什么是通知&#xff1f; Notification通知是在移动应用APP提供给用户的消息提示&#xff0c;是在移动系统的通知栏中显示。当移动应用不在运行时或者在后台状态下&#xff0c;通过发布通知…

2023-简单点-树莓派的config.txt文件解析

config.txt文件解析 注意事项什么时候去读取这个配置文件呢&#xff1f;如何查看配置情况&#xff1f;举例某些常见参数常见硬件参数camera_auto_detectdisplay_auto_detect dtparamarm_boost (Raspberry Pi 4 Only)start_file, fixup_filecmdlinearm_64bitotg_mode (Raspberry…

【小白进阶】Linux 调试大法——gdb

初衷 gdb调试是每一个后端开发工程师所必备的技能&#xff0c;我们工作总是会用gdb协助我们去分析和调试问题。但是大部分同学的技能仅停留在最基础的查看问题。即gdb program -->r --> 问题复现 --> bt 查看源码中的哪一行出现了错误。再稍微熟练点的&#xff0c;可能…