自学内容网 自学内容网

微服务自定义过滤器

一、网关登录校验        

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

1.1、鉴权思路分析

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

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

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

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

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

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

1.2、网关过滤器

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

 

如图所示:

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

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

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

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

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

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

/**
 * 处理请求并将其传递给下一个过滤器
 * @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

       2. 从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:将变量按照一定的顺序进行返回

        

        


原文地址:https://blog.csdn.net/MuYuZiBuYan/article/details/144750951

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!