关闭

SpringCloud GateWay的原理浅析及鉴权使用

古今自逍遥 1年前 ⋅ 454 阅读

1.GateWay

使用网关的好处:

  1. 它提供了一个统一的入口,客户端无需知道每台服务器的ip地址,只需要给网关发送请求。
  2. 可以对各个微服务之间进行流量管控,服务熔断,降级等机制。
  3. 协议适配
  4. 安全防护,ip黑名单,鉴权等。

而我们一直用到的网关的功能差不多就是统一访问入口、请求路由、请求限流和鉴权。

2.GateWay网关的路由规则routes

1.id:该路由规则的唯一id,标志,名字
2.uri:需要被路由到的uri地址,比如http://www.baidu.com ,那么这个请求就会被路由到百度上去。也可以是 lb://application.name 这样的形式,lb就是load banlance负载均衡的意思,application.name填的就是要路由到的服务的名称,那么该网关就能自动的将请求负载均衡到指定的服务上去了。
3.predicates:断言(判断条件),一个请求过来就是通过predicates来判断是否可以路由到指定的route上去的,而predicates可以去通过Host、Path、Query、Method、Cookie、Header、DateTime、RemoteAddr等去进行断言,可以单个使用,也可以多个组合在一起进行使用。
4.filters:过滤器,通过pre和post方法可以对请求发送到指定服务前和请求从指定服务返回后,对该请求的数据进行修改。

    gateway:
      routes:
        - id: product_route
          uri: lb://lgmall-product
          predicates:
            - Path=/api/product/**  #匹配对应的路径,并且会将匹配到的路径添加到uri的后面
            - Query=id              #请求的参数中包含一个叫id的参数
            - Query=id,5            #请求的参数中包含一个叫id的参数且id的值为5
            - Method=Post           #请求方法的类型为Post请求
            - After=2021-05-01T12:00:00.000+08:00[Asia/Shanghai] #匹配所有请求的时间在2021年5月1日12点后的请求
            - RemoteAddr=192.168.56.1/0    #匹配所有远程请求地址是192.168.56.1,子网掩码是0的请求
            - Header=id,\d+         #匹配所有header中包含id为数字的请求,\d+是一个正则表达式,表示任意数字
          filters:
            - RewritePath=/api/(?<segment>/?.*),/$\{segment} #将前面一段路径重写为后面一段路径,这里的意思是把原路径中的/api给去掉
            - PrefixPath=/product   #将/product加在请求路径的前面
            - StripPrefix=2         #去掉前面2个/和它后面的路径,如/A/B/C,就会变成/C
            - SetPath=/product/{segment}   #设置路径,这里再前面需要加一个-Path=api/product/{segment},这样segment会存储到一个map中,设置路径是就能或者到
            - AddRequestParameter=id,1     #给请求添加参数id=1
            - SetStatus=404         #返回页面状态码status code为404,即使它是一个正常的请求

3.网关的执行流程

这张是官网上的流程图:

在这里插入图片描述

1.首先客户端发送请求过来的时候,会通过GateWay Handler Mapping去对请求进行路由route的映射;
2.如果映射到了,就会再调用网关处理程序GateWay Web Handler进行处理;
3.那么Handler就会通过这个route的一系列Filter对该请求进行pre处理,处理完成以后最终路由到一个具体的服务上去;
4.当请求从该服务返回的时候,又会通过这一系列Filter对请求进行post处理,再从handler到Mapping进行返回给该客户端。

4.GatewayFilter和GlobalFilter

网关过滤器根据作用范围可以分为GatewayFilter和GlobalFilter:
GatewayFilter:在配置文件中,指定路由下添加的Filter都是GatewayFilter,它只对当前的路由生效。除非可以通过spring.cloud.default-filters来进行配置,将其作用在全局上。
GloablFilter:这是全局过滤器,不需要在配置文件中去进行指定,它会作用在所有的路由上。通过GateWayFilterAdapter包装成GateWayFilterChain可识别的过滤器,他也是请求uri转换为真实请求地址的核心过滤器。

5.自定义Filter,鉴权

通过上面的介绍,我们也能够知道网关的工作流程了,那么当我们使用网关去进行鉴权的时候,就可以通过自定义一个全局的过滤器来实现。

/**
 * 鉴权使用的Filter
 */
@Component
public class AccessFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {
            String currentMemberId = MemberInfoUtil.getCurrentMemberId();
            //todo 继续在这里判断和鉴权,如果鉴权失败了,也会返回earlyResponse;
        } catch (InvalidTokenException e) {
            return earlyResponse(e.getMessage(), exchange);
        }
        //返回这个chain.filter会使得继续执行下面的filter
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    private Mono<Void> earlyResponse(String message, ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().add("Content-Type", "application/json;charset=utf-8");
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        String message2 = "{\"message\":\"" + message + "\"}";
        DataBuffer buffer = response.bufferFactory().wrap(message2.getBytes());
        //返回这个,就不会再执行filter了,就是真的返回了
        return response.writeWith(Mono.just(buffer));
    }
}
  1. 在这里我们定义一个类AccessFilter 继承自GlobalFilter和 Ordered,然后将其使用@component注解加入到spring容器中,那么这个全局过滤器就生效了。
  2. 不同于定义GateWayFilter,使用它需要手动的进行配置路由规则,将这个Filter加入到指定的路由规则中去,而自定义GlobalFilter是不需要这样做的。
  3. 在重载的filter方法中,我们只需要获取用户信息,进行权限验证的判断,有权限则返回chain.filter(exchange)方法,使得Filter链可以接着执行下去。
  4. 如果判断出权限不足或者无法验证身份,则会返回一个response.writeWith(Mono.just(buffer)),那么这个response就会直接返回,不会再进行后面的操作了。

6.网关限流
GateWay限流是采用的令牌桶的方式进行限流的,需要配合redis来使用,他有以下几种限流方式:1.根据URI限流;2.根据参数限流;3.根据IP限流;


全部评论: 0

    我有话说: