如何为Spring Cloud Gateway加上全局过滤器

既然是一个网关。那么全局过滤器肯定是少不了的一个存在。像是鉴权、认证啥的不可能每个服务都做一次,一般都是在网关处就搞定了。
Zuul他就有很强大的过滤器体系来给人使用。
Gateway当然也不会差这么点东西。
对于SpringCloud体系来说,一切的实现都是那么的简单。那么废话不多说,直接开始写起来。
 
Gateway内部有一个接口 名为GlobalFilter,这个就是Gateway的全局过滤器接口,只要在应用中实现此接口后注册为Spring的Bean,背后就会帮你将这个实现注册到全局过滤器链条里边去。
我这里就简单的写了个模拟鉴权的过滤器实现:

@Component
public class AuthFilter implements GlobalFilter, Ordered {
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    String token = exchange.getRequest().getHeaders().getFirst("Authorization");
    //不为空则通过
    if (!StringUtils.isEmpty(token)) return chain.filter(exchange);
    ServerHttpResponse response = exchange.getResponse();
    // 封装错误信息
    Map<String, Object> responseData = Maps.newHashMapWithExpectedSize(3);
    responseData.put("code", HttpStatus.UNAUTHORIZED.value());
    responseData.put("message", "Token is empty");
    responseData.put("cause", "Token is empty");
    // 将信息转换为 JSON
    ObjectMapper objectMapper = new ObjectMapper();
    byte[] data = new byte[0];
    try {
      data = objectMapper.writeValueAsBytes(responseData);
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    // 返回错误信息json
    DataBuffer buffer = response.bufferFactory().wrap(data);
    response.setStatusCode(HttpStatus.UNAUTHORIZED);
    response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
    return response.writeWith(Mono.just(buffer));
  }
  //最后执行
  @Override
  public int getOrder() {
    return Ordered.LOWEST_PRECEDENCE;
  }
}

虽说是鉴权,但实际上我这就是个简单的demo而已。想知道真正的Spring Security鉴权/认证怎么写?
我以前写的这个:https://github.com/skypyb/code_demo/tree/master/spring-security-demo 应该可以帮助你。
 
看我写的这个过滤器内部实现哈,其实就是拿出Request Header中的 Authorization字段(token) 然后判断是否存在。不存在就返回错误,存在就交给链条中的下一个过滤器。
 
过滤器其实也没啥好说的,那么说说限流。
关于限流这个东西,常见的算法就是漏桶和令牌桶了,对于一个应用单机限流来说也复杂不到哪儿去。
靠着google guava包里的RateLimiter工具都能搞定大多数场景了。
不过既然人家Gateway好心好意给你搞了个限流的实现。那么还是尊重他用一下。
由于Gateway是用的Redis和lua脚本实现了令牌桶的算法,那么先导入几个需要的依赖:

    <!--Redis begin-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
    </dependency>
    <!--Redis end-->

既然是Redis,那还是先配一下Redis序列化先:

@Configuration
public class RedisConfig {
  @Bean
  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    redisTemplate.setKeySerializer(stringRedisSerializer);
    redisTemplate.setHashKeySerializer(stringRedisSerializer);
    redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
    redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    redisTemplate.setConnectionFactory(connectionFactory);
    return redisTemplate;
  }
}

万事俱备,开始进行限流的具体实现了。
 
既然是限流,那么也得有个限流策略
是根据用户来限流呢?还是说根据请求路径限流?或者是IP限流?
不过这个都是由需求来决定了,我这就简单的写个根据IP来限流的。
人家也给你封装完毕了,只需要你自己实现KeyResolver这个接口就可以。
由于实现这个一般来说也就一行代码,所以我就不写个单独的类去实现了,而是直接写在配置类里边。

@Configuration
public class GatewayRateLimiterConfig {
  /**
   * Gateway通过内置的RequestRateLimiter过滤器实现限流,用的是令牌桶算法,借助Redis保存中间数据
   * 这里自定义一个KeyResolver
   * 作用是对来源ip进行限流
   */
  @Bean(value = "ipKeyResolver")
  public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
  }
}

看,我其实只需要返回我需要限制的东西就可以了。我这里提取到用户的IP将其返回,即可实现通过ip来进行限流的策略。
不过限流相关的配置写了,那也得用起来。
这个怎么用起来? 其实直接在配置文件里配置就OK了

spring:
 application:
  # 应用名称
  name: sc-demo-alibaba-gateway
 cloud:
  nacos:
   discovery:
    server-addr: 192.168.3.105:8848 #注册进nacos
  # 使用 Sentinel 作为熔断器
  sentinel:
   transport:
    port: 18102
    dashboard: 192.168.3.105:8858
  # 路由网关配置
  gateway:
   # 这里是设置与服务注册发现组件结合,这样可以采用服务名的路由策略
   discovery:
    locator:
     enabled: true
   # 配置路由规则
   routes:
    - id: ROUTER#sc-demo-alibaba-consumer #这个是路由ID,需要保证在所有路由定义中唯一,值随便写就是了
     # 采用 LoadBalanceClient 方式请求,以 lb:// 开头,后面的是注册在 Nacos 上的服务名
     uri: lb://sc-demo-alibaba-consumer
     predicates:
      # Method ,这里是匹配 GET 和 POST 请求
      - Method=GET,POST
     filters:
      - name: RequestRateLimiter
       args:
        redis-rate-limiter.burstCapacity: 20
        redis-rate-limiter.replenishRate: 5
        key-resolver: '#{@ipKeyResolver}'
    - id: ROUTER#sc-demo-alibaba-provider
     uri: lb://sc-demo-alibaba-provider
     predicates:
      - Method=GET,POST
 #Redis配置
 redis:
  host: 192.168.3.105
  port: 6379
  #Redis连接池配置
  jedis:
   pool:
    min-idle: 0
    max-idle: 8
    max-active: 8
    max-wait: -1ms
server:
 port: 8888
feign:
 sentinel:
  enabled: true
management:
 endpoints:
  web:
   exposure:
    include: "*"
# 配置日志级别,方别调试
logging:
 level:
  org.springframework.cloud.gateway: debug

这里可以看到,除了Redis配置 ( spring.redis.** )以外。
主要就是对于Getway的配置。
在Gateway路由配置中,设置了一个filters参数。
这个是为了指定路由的各种过滤器的。这个参数也有很多种,可以参考官方讲解: https://cloud.spring.io/spring-cloud-gateway/2.0.x/single/spring-cloud-gateway.html#gateway-route-filters

我这就是指定了一个RequestRateLimiter,请求限流。

  • redis-rate-limiter.burstCapacity: 20

这个参数表示突发容量,即每秒可以最大通过多少次请求

  • redis-rate-limiter.replenishRate: 5

这个是令牌桶的补充速度,每秒往桶里边放几个令牌

  • key-resolver: ‘#{@ipKeyResolver}'

这个就是用上KeyResolver的具体实现了,这里用spel表达式指定我写的那个ip限制类

准备好之后将应用启动就完事了,想测的话可以用jmeter测测看,或者将请求限制写的更小一点,在网页上狂按f5也行。

以上就是如何为Spring Cloud Gateway加上全局过滤器的详细内容,更多关于Spring Cloud Gateway添加全局过滤器的资料请关注我们其它相关文章!

时间: 2021-03-12

详解SpringCloud Gateway之过滤器GatewayFilter

在Spring-Cloud-Gateway之请求处理流程文中我们了解最终网关是将请求交给过滤器链表进行处理,接下来我们阅读Spring-Cloud-Gateway的整个过滤器类结构以及主要功能 通过源码可以看到Spring-Cloud-Gateway的filter包中吉接口有如下三个,GatewayFilter,GlobalFilter,GatewayFilterChain,下来我依次阅读接口的主要实现功能. GatewayFilterChain 类图 代码 /** * 网关过滤链表接口 * 用

spring cloud gateway 全局过滤器的实现

全局过滤器作用于所有的路由,不需要单独配置,我们可以用它来实现很多统一化处理的业务需求,比如权限认证,IP访问限制等等. 接口定义类:org.springframework.cloud.gateway.filter.GlobalFilter public interface GlobalFilter { Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain); } gateway自带的GlobalFilte

Spring Cloud Gateway全局通用异常处理的实现

为什么需要全局异常处理 在传统 Spring Boot 应用中, 我们 @ControllerAdvice 来处理全局的异常,进行统一包装返回 // 摘至 spring cloud alibaba console 模块处理 @ControllerAdvice public class ConsoleExceptionHandler { @ExceptionHandler(AccessException.class) private ResponseEntity<String> handleAc

Spring Cloud Gateway全局异常处理的方法详解

前言 Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式.Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等

Spring Cloud Gateway入门解读

Spring Cloud Gateway介绍 前段时间刚刚发布了Spring Boot 2正式版,Spring Cloud Gateway基于Spring Boot 2,是Spring Cloud的全新项目,该项目提供了一个构建在Spring 生态之上的API网关,包括:Spring 5,Spring Boot 2和Project Reactor. Spring Cloud Gateway旨在提供一种简单而有效的途径来发送API,并为他们提供横切关注点,例如:安全性,监控/指标和弹性.当前最新的

Spring Cloud Gateway使用Token验证详解

引入依赖 <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <ty

Spring Cloud GateWay 路由转发规则介绍详解

Spring在因Netflix开源流产事件后,在不断的更换Netflix相关的组件,比如:Eureka.Zuul.Feign.Ribbon等,Zuul的替代产品就是SpringCloud Gateway,这是Spring团队研发的网关组件,可以实现限流.安全认证.支持长连接等新特性. Spring Cloud Gateway Spring Cloud Gateway是SpringCloud的全新子项目,该项目基于Spring5.x.SpringBoot2.x技术版本进行编写,意在提供简单方便.可

详解Spring Cloud Gateway基于服务发现的默认路由规则

1.Spring Gateway概述 1.1 什么是Spring Cloud Gateway Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式.Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由

Spring Cloud Gateway 服务网关快速实现解析

Spring Cloud Gateway 服务网关 API 主流网关有NGINX.ZUUL.Spring Cloud Gateway.Linkerd等:Spring Cloud Gateway构建于 Spring 5+,基于 Spring Boot 2.x 响应式的.非阻塞式的 API.同时,它支持 websockets,和 Spring 框架紧密集成,用来代替服务网关Zuul,开发体验相对来说十分不错. Spring Cloud Gateway 是 Spring Cloud 微服务平台的一个子

spring cloud gateway 限流的实现与原理

在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方面是为了防止网络攻击. 常见的限流方式,比如Hystrix适用线程池隔离,超过线程池的负载,走熔断的逻辑.在一般应用服务器中,比如tomcat容器也是通过限制它的线程数来控制并发的:也有通过时间窗口的平均速度来控制流量.常见的限流纬度有比如通过Ip来限流.通过uri来限流.通过用户访问频次来限流. 一般限流都是在网关这一层做,比如Nginx.Openresty.kong.zuul.Spring

详解Spring Cloud Gateway 限流操作

开发高并发系统时有三把利器用来保护系统:缓存.降级和限流. API网关作为所有请求的入口,请求量大,我们可以通过对并发访问的请求进行限速来保护系统的可用性. 常用的限流算法比如有令牌桶算法,漏桶算法,计数器算法等. 在Zuul中我们可以自己去实现限流的功能 (Zuul中如何限流在我的书 <Spring Cloud微服务-全栈技术与案例解析>  中有详细讲解) ,Spring Cloud Gateway的出现本身就是用来替代Zuul的. 要想替代那肯定得有强大的功能,除了性能上的优势之外,Spr