【云原生&微服务>SCG网关篇八】Spring Cloud Gateway三种自定义Filter、GlobalFilter的方式

网友投稿 406 2022-08-23

【云原生&微服务>SCG网关篇八】Spring Cloud Gateway三种自定义Filter、GlobalFilter的方式

文章目录

​​一、前言​​​​二、自定义Filter​​

​​1、继承自AbstractNameValueGatewayFilterFactory实现日志记录功能​​​​2、继承自AbstractGatewayFilterFactory实现日志记录功能​​

​​三、自定义GlobalFilter​​

​​1、自定义GlobalFilter实现鉴权功能​​

​​四、总结​​

一、前言

至此微服务网关系列文章已出:

​​【云原生&微服务>SCG网关篇一】为什么要有网关、生产环境如何选择网关​​​​云原生&微服务>SCG网关篇二】生产上那些灰度发布方式​​​​【云原生&微服务>SCG网关篇三】Spring Cloud Gateway是什么、详细使用案例​​​​云原生&微服务>SCG网关篇四】Spring Cloud Gateway内置的11种PredicateFactory如何使用​​​​【云原生&微服务>SCG网关篇五】Spring Cloud Gateway自定义PredicateFactory​​​​【云原生&微服务>SCG网关篇六】Spring Cloud Gateway内置的18种Filter使用姿势​​​​【云原生&微服务>SCG网关篇六】Spring Cloud Gateway基于内置Filter实现限流、熔断、重试​​

聊了以下问题:

为什么要有网关?网关的作用是什么?网关的分类?网关的技术选型?使用网关时常用的灰度发布方式有哪些?Spring Cloud Gateway是什么?详细使用案例?Spring Cloud Gateway内置的11种PredicateFactory如何自定义PredicateFactory?Spring Cloud Gateway内置的18种常用的FilterSpring Cloud Gateway基于内置Filter实现限流、熔断、重试

本文接着聊Spring Cloud Gateway如何自定义Filter、GlobalFilter

PS:SpringCloud版本信息:

2.4.2 2020.0.1 2021.1 org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${spring-cloud-alibaba.version} pom import

二、自定义Filter

GatewayFilterFactory仅能作用于单个路由Route。下面自定义一个Filter实现日志记录的功能;

1、继承自AbstractNameValueGatewayFilterFactory实现日志记录功能

1> AbstractNameValueGatewayFilterFactory子类MyLogNameValueGatewayFilterFactory:

package com.saint.gateway.filter;import lombok.extern.slf4j.Slf4j;import org.springframework.cloud.gateway.filter.GatewayFilter;import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;import org.springframework.stereotype.Component;import reactor.core.publisher.Mono;/** * 统一日志记录Filter * 继承自AbstractNameValueGatewayFilterFactory,内置了两个参数:name和value; * * @author Saint */@Component@Slf4jpublic class MyLogNameValueGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory { @Override public GatewayFilter apply(NameValueConfig config) { return ((exchange, chain) -> { // Filter的前置处理Prev log.info("MyLogGatewayFilterFactory [Pre] Filter Request, config.getName() = " + config.getName()); return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 在then方法中是请求执行结束之后的后置处理,即Filter的POST log.info("MyLogGatewayFilterFactory [Post] Response Filter"); })); }); }}

2> application.yml中给Route配置Filter:

server: port: 9999spring: cloud: gateway: routes: - id: add_request_parameter_route uri: predicates: - Path=/** filters: # 自定义过滤器的名字,即:MyLogNameValueGatewayFilterFactory - name: MyLogNameValue args: name: Saint_name value:

3> 测试:

访问接口:​​AbstractGatewayFilterFactory子类MyLogGatewayFilterFactory:

package com.saint.gateway.filter;import lombok.extern.slf4j.Slf4j;import org.springframework.cloud.gateway.filter.GatewayFilter;import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;import org.springframework.stereotype.Component;import reactor.core.publisher.Mono;/** * 统一日志记录Filter * AbstractGatewayFilterFactory,可以自定义参数; * * @author Saint */@Component@Slf4jpublic class MyLogGatewayFilterFactory extends AbstractGatewayFilterFactory { public MyLogGatewayFilterFactory() { super(MyConfig.class); } @Override public GatewayFilter apply(MyConfig config) { return ((exchange, chain) -> { // Filter的前置处理Prev log.info("MyLogGatewayFilterFactory [Pre] Filter Request, config.getName() = " + config.getName()); return chain.filter(exchange).then(Mono.fromRunnable(() -> { // 在then方法中是请求执行结束之后的后置处理,即Filter的POST log.info("MyLogGatewayFilterFactory [Post] Response Filter"); })); }); } /** * MyConfig只是一个配置类,该类中只有一个属性name。这个属性可以在yml文件中使用 */ public static class MyConfig { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }}

2> application.yml中给Route配置Filter:

server: port: 9999spring: cloud: gateway: routes: - id: add_request_parameter_route uri: predicates: - Path=/** filters: # 自定义过滤器的名字,即:MyLogGatewayFilterFactory - name: MyLog args: name:

3> 测试:

访问接口:​​GlobalFilter实现类AuthFilter:

package com.saint.gateway.filter;import org.apache.commons.lang3.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.Ordered;import org.springframework.org.springframework.org.springframework.org.springframework.org.springframework.stereotype.Component;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono;import java.util.List;/** * 对所有路由生效的GlobalFilter,鉴权使用 * * @author Saint */@Componentpublic class AuthFilter implements GlobalFilter, Ordered { private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class); @Value("#{'${auth.skip.urls:}'.split(',')}") private List skipAuthUrls; /** * 存放token信息的请求头属性 */ public static final String COOKIE_NAME_TOKEN = "saint_token"; @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { //1.获取请求对象 ServerHttpRequest request = exchange.getRequest(); //2.获取响应对象 ServerHttpResponse response = exchange.getResponse(); //3.判断 是否需要直接放行 logger.info("uri: {}", request.getURI()); if (skipAuthUrls.contains(request.getURI().toString())) { return chain.filter(exchange); } //4 校验 //4.1 从头header中获取令牌数据 String token = request.getHeaders().getFirst(COOKIE_NAME_TOKEN); if (StringUtils.isEmpty(token)) { //4.2 从cookie中中获取令牌数据 HttpCookie first = request.getCookies().getFirst(COOKIE_NAME_TOKEN); if (first != null) { token = first.getValue();//就是令牌的数据 } } if (StringUtils.isEmpty(token)) { //4.3 从请求参数中获取令牌数据 token = request.getQueryParams().getFirst(COOKIE_NAME_TOKEN); } if (StringUtils.isEmpty(token)) { //4.4. 如果没有数据 没有登录,要重定向到登录到页面 response.setStatusCode(HttpStatus.FORBIDDEN);//403 // 4.5. 在响应头里添加鉴权失败信息 response.getHeaders().set("auth_error", "xxxx"); return response.setComplete(); } //TODO 5 解析令牌数据 ( 判断解析是否正确,正确 就放行 ,否则 结束) try { logger.info("authed user info: {}", "*****"); } catch (Exception e) { logger.error("parse token error:", e); //解析失败 response.setStatusCode(HttpStatus.FORBIDDEN); return response.setComplete(); } // 6 将token添加到头信息,传递给后续的服务 request.mutate().header(COOKIE_NAME_TOKEN, token); return chain.filter(exchange); } /** * 这里表示将当前Filter放在过滤链的最前面 * * @return */ @Override public int getOrder() { return 0; }}

AuthFilter不仅实现了GlobalFilter对所有的Route进行过滤操作,还要实现​​Ordered​​接口,并重写getORder()方法返回0,表示最先执行当前AuthFilter。

2> pom.xml中引入commons-lang3:

org.apache.commons commons-lang3 3.12.0

3> application.yml文件中设置不走鉴权的URI:

auth: skip: urls: / GlobalFilter的方式,分别为:继承AbstractNameValueGatewayFilterFactory、继承AbstractGatewayFilterFactory、实现GlobalFilter接口。下文接着聊Spring Cloud Gateway 和Nacos的集成。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:“营销大师”仁和药业浮出水面,重营销、代工,成违规大户!(仁和药业的销售模式)
下一篇:【云原生&微服务>SCG网关篇九】Spring Cloud Gateway集成Nacos实现请求负载详细案例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~