天天看點

【Spring Cloud Gateway專題】三、自定義gatewayfilter實作AddRequestHeader1、前言2、使用yaml配置方式3、使用RouteLocator程式設計方式4、使用自定義gatewayfilter方式

1、前言

實際項目中存在這樣一個場景,使用Spring Cloud Gateway建設一個網關,該網關負責代理所有業務系統的對外通路請求。若外部服務需要授權(下文中的passID和passToken)才能通路,那麼該網關可以統一處理該問題。

以下引出添加AddRequestHeader的幾種方式,以及存在的限制。

2、使用yaml配置方式

采用yaml方式配置 ,通路csdn網站,X-Request-red = blue,該方式适用于已知資料的添加。

spring:
  application:
    name: gateway-application
  cloud:
    # Spring Cloud Gateway 配置項,對應 GatewayProperties 類
    gateway:
      # 路由配置項,對應 RouteDefinition 數組
      routes:
        - id: csdn1 # 路由的編号
          uri: https://blog.csdn.net # 路由到的目标位址,隻能到域名部分 https://blog.csdn.net/dear_little_bear
          predicates: # 斷言,作為路由的比對條件,對應 RouteDefinition 數組
            - Path=/csdn1
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-red, blue
           

3、使用RouteLocator程式設計方式

采用RouteLocator程式設計方式 ,通路csdn網站,該方式适用于不變的資料(“單例”)的添加。

@Configuration
public class RouteConfiguration {
    @Value("${gateway.csdn.host}")
    private String csdnHost;

    @Value("${gateway.csdn.PaaSID}")
    private String paaSID;

    @Value("${gateway.csdn.PaaSToken}")
    private String paaSToken;

    @Value("${gateway.csdn.nonce}")
    private String nonce;

    @Autowired
    private CsdnRequestFilter csdnRequestFilter;

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) throws UnsupportedEncodingException {
        String timeTamp = String.valueOf(System.currentTimeMillis() / 1000);
        String signature = SecureUtil.sha256(timeTamp + nonce + paaSToken);

        return builder.routes()
                .route(r -> r.path("/csdn2/**")
                        .filters(f ->
                                f.stripPrefix(1)
                                .addRequestHeader("x-tif-nonce", nonce)
                                .addRequestHeader("x-tif-signature", signature)
                                .addRequestHeader("x-tif-paasid", paaSID)
                                .addRequestHeader("x-tif-timestamp", timeTamp))
                        .uri(csdnHost)
                        .order(2))
                /*.route(r -> r.path("/csdn3/**")
                        .filters(f->f.stripPrefix(1)
                                .filter(csdnRequestFilter))
                        .uri(csdnHost)
                        .order(3))*/
                .build();
    }
}
           

使用Postman請求:

【Spring Cloud Gateway專題】三、自定義gatewayfilter實作AddRequestHeader1、前言2、使用yaml配置方式3、使用RouteLocator程式設計方式4、使用自定義gatewayfilter方式

兩次請求結果(不同時間點):

2020-04-04 14:16:15.141 DEBUG 10204 — [ctor-http-nio-3] o.s.c.g.h.RoutePredicateHandlerMapping : Mapping [Exchange: GET http://localhost:8888/csdn2] to Route{id=‘c3c865da-0fc2-47e3-aef2-55864afd626f’, uri=https://blog.csdn.net:443, order=2, predicate=Paths: [/csdn2/**], match trailing slash: true, gatewayFilters=[[[StripPrefix parts = 1], order = 0], [[AddRequestHeader x-tif-nonce = ‘123456789abcdefg’], order = 0], [[AddRequestHeader x-tif-signature = ‘3dee7471fe6b71a2b66f3b187c8cca844c3aef47afa4020f7df3b5c386015955’], order = 0], [[AddRequestHeader x-tif-paasid = ‘csdndemo’], order = 0], [[AddRequestHeader x-tif-timestamp = ‘1585980879’], order = 0]], metadata={}}
2020-04-04 14:20:14.343 DEBUG 10204 — [ctor-http-nio-3] o.s.c.g.h.RoutePredicateHandlerMapping : Mapping [Exchange: GET http://localhost:8888/csdn2] to Route{id=‘c3c865da-0fc2-47e3-aef2-55864afd626f’, uri=https://blog.csdn.net:443, order=2, predicate=Paths: [/csdn2/**], match trailing slash: true, gatewayFilters=[[[StripPrefix parts = 1], order = 0], [[AddRequestHeader x-tif-nonce = ‘123456789abcdefg’], order = 0], [[AddRequestHeader x-tif-signature = ‘3dee7471fe6b71a2b66f3b187c8cca844c3aef47afa4020f7df3b5c386015955’], order = 0], [[AddRequestHeader x-tif-paasid = ‘csdndemo’], order = 0], [[AddRequestHeader x-tif-timestamp = ‘1585980879’], order = 0]], metadata={}}

我們發現timestamp和signature都沒有發生變化,即便在customRouteLocator上加上Scope,依然無效。檢視源碼後發現,當我們啟動了Spring Cloud Gateway之後,該RouteLocator就會建立,并且不會重複new。但這不是我們想要的結果。

4、使用自定義gatewayfilter方式

(1) 自定義一個CsdnRequestFilter實作GatewayFilter,CsdnRequestFilter 代碼如下:

@Component
public class CsdnRequestFilter implements GatewayFilter, Ordered {

    @Value("${gateway.csdn.PaaSID}")
    private String paaSID;

    @Value("${gateway.csdn.PaaSToken}")
    private String paaSToken;

    @Value("${gateway.csdn.nonce}")
    private String nonce;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String timeTamp = String.valueOf(System.currentTimeMillis() / 1000);
        String signature = SecureUtil.sha256(timeTamp + nonce + paaSToken);
        System.out.print("自定義過濾器:timeTamp:"+timeTamp+";signature:"+signature);
        //提取應用賬戶及應用令牌,鑒權
        ServerHttpRequest request = exchange.getRequest().mutate()
                .header("x-tif-nonce", nonce)
                .header("x-tif-signature", signature)
                .header("x-tif-paasid", paaSID)
                .header("x-tif-timestamp", timeTamp)
                .build();

        return chain.filter(exchange.mutate().request(request).build());
    }

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

           

(2) 在RouteLocator類中添加該gatewayfilter,代碼如下:

return builder.routes()
                .route(r -> r.path("/csdn3/**")
                        .filters(f->f.stripPrefix(1)
                                .filter(csdnRequestFilter))
                        .uri(csdnHost)
                        .order(3))
                .build();
           

兩次請求結果如下:

自定義過濾器:timeTamp:1585982693;signature:110ad2c949fb9e9afe2c8f98a81f6f445fd85ad43e0dec1ab555dae8f06b8f62 2020-04-04 14:44:53.180
自定義過濾器:timeTamp:1585980894;signature:265ff5cbac42c99969403285b897c24e2db59151f456a842669c7e7726fb9c23 2020-04-04 14:14:54.504

發現timeTamp和signature都發生了改變。原因是自定義gatewayfilter會在每次http請求過程中,動态建立。

特别注意

header是readonly類型,是以在CsdnRequestFilter中新增header,采用的是exchange.getRequest().mutate(),該方法将會構造出一個新的ServerHttpRequest。同時,也使用了exchange.mutate() 方法重新構造了一個ServerWebExchange 。

以上希望對你有幫助。

源碼: https://github.com/muziye2013/SpringBoot-Labs 參照 labx-08/labx-08-ex-gateway-demo01章節

繼續閱讀