0
点赞
收藏
分享

微信扫一扫

SpringCloudAlibaba之gateway网关(九)

简介

Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API,并为它们提供跨领域的关注点,例如:安全性、监控/度量和弹性。

Spring Cloud Gateway构建在Spring Boot 2.x、 Spring WebFlux和Project Reactor。因此,当您使用Spring Cloud Gateway时,许多您熟悉库(例如Spring Data and Spring Security)和模式可能不需使用。

Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty运行时。它不能在传统的Servlet容器中工作,也不能在构建为WAR时工作。

概念

Route(路由): 网关的基本构造块。它由一个ID、一个目标URI、一组断言和一组过滤器定义。如果断言为true,则匹配路由。

Predicate(断言): 一个Java8功能断言。 输出类型是Spring Framework ServerWebExchange。 你可以匹配任何来HTTP请求, 例如headers和参数.

Filter(过滤器):这里有很多factory构建GatewayFilter类。你可以在发送到下游请求之前或者之后修改请求和返回。

如何工作

下图对Spring Cloud Gateway工作进行了一个概述:

 Clients向Spring Cloud Gateway发出请求。如果Gateway Handler Mapping检测到一个请求匹配路由,请求将被发送给Gateway Web Handler。Handler通过Filter处理请求。Filter被虚线分隔的原因是,Filter可以在代理请求发送之前和之后运行。先执行发送之前处理,然后Proxy Filter再运行,最后执行发送之后的处理。

配置Predicate Factories和Filter Factories

有两种方法可以配置Predicate和Filter快捷方式和完全参数。下面的大多数示例都使用快捷方式。

完整参数

完整参数更显是一个标准的yaml配置包含名称和值。通常,有name键和args键。args键是键-值的map配置Predicate和Filter。

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

快捷方式

快捷方式配置由Predicate名称、等号(=)和逗号(,)分隔的参数值识别。

 application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

RoutePredicateFactory

RoutePredicateFactories包含了11种配置,具体怎么配置不一一说明了,这里只讲述下支持那些配置。

GatewayFilterFactory

支持23种方式,由于太多,将不一一列举。

由于篇幅原因,RoutePredicateFactory和GatewayFilterFactory使用方式未一一列举,这里

链接,方便用到是查看样例。

快速使用

创建名称为gateway的module,pom.xml配置:

<!--引入nacos client的依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- gateway 网关依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

application.yml配置

server:
  port: 7007
spring:
  application:
    name: GATEWAY
  cloud:
    nacos:
      discovery:
        namespace: ec6004af-f122-4ed1-b6d6-5d77ea5d5c94
        server-addr: 192.168.43.85:8845,192.168.43.229:8846,192.168.43.251:8847
    gateway:
      routes:
        - id: myRoute
          uri: lb://USERS
          predicates:
            - Path=/service-order/**
          filters:
            - StripPrefix=1

uri中使用lb://USERS,其中lb表示使用nacos中心注册的服务名,这样就不需知道微服务的地址和端口,只需知道其他注册到nacos的服务名称就可以了。

path对service-order路径下所有请求进行拦截访问,访问名称为USERS的微服务。即http://USERS/service-order/**。

StripPrefix表示去掉一程路径,即变成了http://USERS/**。

简单的说就是方位http://网关:7007//service-order/**,最后被反射代理去访问了http://USERS/**目标地址。其中USERS是对应微服务的访问IP+端口。

问题

这里有一个问题,也是常见的问题,就是我们所有的服务都可以访问网关,也可以直接访问目标微服务,那如何屏蔽用户直接访问目标微服务呢?

有两种办法,

1、服务器层次更改,直接屏蔽其他微服务端口,对外不提供方位,只应许内部访问,对外只提供网关端口。(推荐使用这种方式)

2、代码层次,使用网关,对所有经过网关请求进行拦截,请求头添加参数,每个微服务进度请求进行拦截,去解析请求是否存在该参数,无这是为非法入侵请求。

网关拦截代码

package com.juwusheng.gateway;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author lhq
 * @date 2022年04月07日 下午5:37
 */
@Configuration
public class TokenFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        /**
         * 可增加令牌等相关信息进行校验
         * 这里创建一个令牌,设置有效期,缓存到redis数据库上,
         * 实际调用的微服务端去redis查看是否有相关令牌
         */
        ServerHttpRequest req = exchange.getRequest().mutate()
                .header("from", "gateway").build();
        return chain.filter(exchange.mutate().request(req.mutate().build()).build());

    }
}

每个微服务对应的拦截

package com.juwusheng.products;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author lhq
 * @date 2022年04月07日 下午5:59
 */
@EnableWebMvc
@Configuration
public class InterceptorConfigure implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(new GlobalInterceptor());
    }
}
package com.juwusheng.products;

import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * @author lhq
 * @date 2022年04月07日 下午5:43
 */
@Component
public class GlobalInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String secretKey = request.getHeader("from");

        if(StringUtils.hasText(secretKey)||secretKey.equals("gateway")){
            response.setContentType("application/json; charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.write("error");
            return false;
        }
        return true;
    }
}
举报

相关推荐

0 条评论