微服务自定义过滤器

一、网关登录校验

单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,不再共享数据。也就意味着每个微服务都需要做登录校验,这显然不可取。

1.1、鉴权思路分析

我们的登录是基于JWT来实现的,校验JWT的算法复杂,而且需要用到秘钥。如果每个微服务都去做登录校验,这就存在着两大问题:

  • 每个微服务都需要知道JWT的秘钥,不安全

  • 每个微服务重复编写登录校验代码、权限校验代码,麻烦

既然网关是所有微服务的入口,一切请求都需要先经过网关。我们完全可以把登录校验的工作放到网关去做,这样之前说的问题就解决了:

  • 只需要在网关和用户服务保存秘钥

  • 只需要在网关开发登录校验功能

1.2、网关过滤器

登录校验必须在请求转发到微服务之前做,否则就失去了意义。而网关的请求转发是Gateway内部代码实现的,要想在请求转发之前做登录校验,就必须了解Gateway内部工作的基本原理。

如图所示:

  1. 客户端请求进入网关后由HandlerMapping对请求做判断,找到与当前请求匹配的路由规则(Route ),然后将请求交给WebHandler去处理。
  2. WebHandler则会加载当前路由下需要执行的过滤器链(Filter chain ),然后按照顺序逐一执行过滤器(后面称为**Filter**)。
  3. 图中Filter被虚线分为左右两部分,是因为Filter内部的逻辑分为pre和post两部分,分别会在请求路由到微服务之前 和之后被执行。
  4. 只有所有Filter的pre逻辑都依次顺序执行通过后,请求才会被路由到微服务。
  5. 微服务返回结果后,再倒序执行Filter的post逻辑。
  6. 最终把响应结果返回。

最终请求转发是有一个名为NettyRoutingFilter的过滤器来执行的,而且这个过滤器是整个过滤器链中顺序最靠后的一个。如果我们能够定义一个过滤器,在其中实现登录校验逻辑,并且将过滤器执行顺序定义到 NettyRoutingFilter 之前,这就符合我们的需求了!

网关过滤器链中的过滤器有两种:

  • GatewayFilter :路由过滤器,作用范围比较灵活,可以是任意指定的路由Route.

  • GlobalFilter:全局过滤器,作用范围是所有路由,不可配置。

其实GatewayFilter和GlobalFilter这两种过滤器的方法签名完全一致:

复制代码
/**
 * 处理请求并将其传递给下一个过滤器
 * @param exchange 当前请求的上下文,其中包含request、response等各种数据
 * @param chain 过滤器链,基于它向下传递请求
 * @return 根据返回值标记当前请求是否被完成或拦截,chain.filter(exchange)就放行了。
 */
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

FilteringWebHandler在处理请求时,会将GlobalFilter装饰为GatewayFilter,然后放到同一个过滤器链中,排序以后依次执行。

Gateway内置的GatewayFilter过滤器使用起来非常简单,无需编码,只要在yaml文件中简单配置即可。而且其作用范围也很灵活,配置在哪个Route下,就作用于哪个Route.

1.2.1、自定义过滤器(GlobalFilter)

以**Gateway为例做一次演示**

由于GlobalFilter是一个接口创建一个 MyGlobalFilter 类加**@compoent** 注解注册成spring Bean上并实现GlobalFilter, 并实现filter方法

1.首先在exchange 获取getRequest

  1. 从getRequest中获取请求头

3.使用chain.filter()放行。

过滤器定义就完成了,接下来需要确保我的的过滤器在NettyRoutrngFilter之前执行。

在ider中按下Ctrl+H点击NettyRoutingFilter

我们发现NettyRoutingFilter不仅继承了GlobalFilter还有Ordered。

而Ordered会要求你实现getOrder()方法。返回的返回值数值越小就越快执行,而getOrder()方法的返回值是2147483647也就是最低优先级。

明白了以上原理后我们就明白这么在NettyRoutingFilter之前执行过滤器。首先实现Ordered,并实现getOrder()方法返回值设置为0比2147483647小那么就理所当然优先执行了

接下来我们设置断点测试就会发现得到了所有的请求头

1.2.1、自定义过滤器(GatewayFilter )

自定义GatewayFilter不是直接实现GatewayFilter,而是实现AbstractGatewayFilterFactory

示例:

创建一个PrintAnyGatewayFilterFactory 类并继承AbstractGatewayFilterFactory 继承AbstractGatewayFilterFactory 需要一个泛型我们填写Object即可

在 apply方法中构造你需要的过滤器,由于GatewayFilter是一个接口所以我们就匿名实现。

但是新的问题又来了,我们之前编写了一个全局过滤器,创建的又是匿名内部类,无法继续实现,无法实现Ordered就无法确定顺序。所以提供了一个装饰类OrderedGatewayFilter他同时实现了GlobalFilter和Ordered

需要带顺序的过滤器可以使用 OrderedGatewayFilter装饰类

以上是无参的**GatewayFilter而,有参和无参的不同点在于**

  1. Config:方法自定义配置属性,成员变量名称非常重要
  2. PrintAnyGatewayFilterFactory:将Config字节码传递给父类,父类负责帮我们读取yaml配置
  3. shortcutFieldOrder:将变量按照一定的顺序进行返回

相关推荐
captain3764 小时前
MyBatis(入门5)其他查询操作
java·数据库·spring boot·mybatis
闪亮的路灯5 小时前
Linux 安装mqtt服务mosquitto
linux·运维·服务器
小此方5 小时前
Re:Mysql数据库基础篇(八):详细讲解复合查询、多表查询、自连接、多行、多列子查询与合并查询
数据库·mysql
xszivvvv5 小时前
Mariadb数据库frm文件异常,如何恢复数据
数据库·mariadb
smile_life_6 小时前
MySQL 设置 防止账户被暴力破解
数据库·mysql
ShineWinsu6 小时前
对于Qt:QRadioButton常见属性以及QButtonGroup的解析
数据库·c++·qt·microsoft·gui·qradiobutton·qbuttongroup
测试盐6 小时前
oracle数据库卡顿排查
数据库·oracle
滕州市燕猫虎计算机科技工作室个体工商户7 小时前
MySQL、MVCC、多版本并发控制
数据库·mysql·mvcc·数据库事务
明航咨询-陈老师7 小时前
ITSS运行维护服务能力成熟度认证技术纵深:标准模型、等级路径、2026审核趋势与CS/CMMI对比
服务器·数据库·cmmi
szxinmai主板定制专家7 小时前
X86 工控机 vs RK3588 异构主控:AMR 控制器 BOM、散热、长期运维对比
运维·stm32·单片机·嵌入式硬件·fpga开发·am62x