自定义starter解决请求绕过网关问题

news2024/12/23 3:15:49

引言

微服务项目中网关是一个常见的模块,通过网关的分发可以实现负载均衡、鉴权等操作;但是搭建好网关可以发现,虽然可以通过网关端口请求后端,如果有其他服务的地址依然可以使用其他服务地址绕过网关请求,这里我提供一种思路来实现发送的请求只能通过网关到达对应服务。

思路

首先可以在网关处加一个过滤器,所有经过网关的请求会经过该过滤器在header上加一个参数;;

然后当请求到达某个服务时只需要校验该请求header上有没有对应参数即可。

实现方法也很简单,就是网关一个过滤器,各个微服务一个拦截器即可,但是各个微服务都写个相同的拦截器代码就有些冗余了,这里可以选择使用aop实现,或者可以自定义一个starter来实现。

下面我自定义一个请求校验的starter来实现以上功能;

代码实现

首先在网关模块编写过滤器:

/**
 * 网关请求过滤器
 */
@Component
public class GatewayRequestFilter implements GlobalFilter {

    private static final String TOKEN = "suibianyigezifuchuan";

    private static final String SALT = "yanglingxiao";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = DigestUtils.md5DigestAsHex((SALT + TOKEN).getBytes());
        ServerHttpRequest build = exchange.getRequest()
                .mutate()
                .header(GatewayConstant.GATEWAY_TOKEN_HEADER, token)
                .build();

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

}

创建starter的步骤可以看这个文章:实现自定义springboot的starter

引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.33</version>
</dependency>

创建properties.java文件用于参数的获取

@Data
@ConfigurationProperties(prefix = "cloud.request")
public class CloudRequestAuthProperties {

    /**
     * 请求是否只能通过网关
     */
    private Boolean onlyFetchByGateway = Boolean.FALSE;

    /**
     * 网关添加header的key
     */
    private String gatewayTokenHeader = "";

    /**
     * 鉴权token
     */
    private String gatewayToken = "";

    /**
     * 加密盐值
     */
    private String salt = "";

}

这里我没有想到比较优雅的设计方法,其中的参数其实可以写死在starter中,但是对应的网关过滤器的salt和token等值就必须和这里的一样,为了能灵活定义我想到这个方法,但是这样通样要求网关过滤器的对应参数值和这里的相同,只是可以自己修改参数值了而已。

创建请求拦截器:

/**
 * 请求拦截器
 */
public class CloudRequestAuthInterceptor implements HandlerInterceptor {

    private CloudRequestAuthProperties properties;

    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler){

        if (!properties.getOnlyFetchByGateway()) {
            return true;
        }

        // 获取请求头中的token
        String token = request.getHeader(properties.getGatewayTokenHeader());

        // 获取网关中设置的token
        String gatewayToken = DigestUtils.md5DigestAsHex((properties.getSalt() + properties.getGatewayToken()).getBytes());

        // 比较请求头中的token和网关中的中的是否相同
        if (StringUtils.equals(gatewayToken, token)) {
            return true; // 放行
        } else {
            try {
                response.setCharacterEncoding("utf-8");
                response.setContentType("application/json; charset=utf-8");
                Map<String, Object> resultMap = new HashMap<>();
                resultMap.put("code", 40300);
                resultMap.put("data", "");
                resultMap.put("message", "禁止访问");
                resultMap.put("description", "请通过网关发送请求");
                String jsonMap = JSON.toJSONString(resultMap);
                PrintWriter writer = response.getWriter();
                writer.write(jsonMap);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return false;
        }
    }

    public void setProperties(CloudRequestAuthProperties properties) {
        this.properties = properties;
    }
}

创建了请求拦截器后还需要把该拦截器注册到拦截器集合中,所以需要一个拦截器配置类:

/**
 * 配置拦截器CloudRequestAuthInterceptor
 */
public class CloudRequestAuthInterceptorConfigure implements WebMvcConfigurer {

    private CloudRequestAuthProperties properties;

    // 这里把CloudRequestAuthProperties注入spring管理
    @Autowired
    public void setProperties(CloudRequestAuthProperties properties) {
        this.properties = properties;
    }

    public HandlerInterceptor serverProtectInterceptor() {
        CloudRequestAuthInterceptor interceptor = new CloudRequestAuthInterceptor();
        interceptor.setProperties(properties);
        return interceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(serverProtectInterceptor());
    }
}

最后是将该配置交给spring管理并启用starter的配置:

@EnableConfigurationProperties(CloudRequestAuthProperties.class)
public class CloudRequestAuthAutoConfigure {

    // 这里将拦截器配置类交给spring管理
    @Bean
    public CloudRequestAuthInterceptorConfigure cloudRequestInterceptorConfigure() {
        return new CloudRequestAuthInterceptorConfigure();
    }

}

这一块的代码要注意spring的注入,不要乱加注解结果导致重复注入,这里我踩坑在拦截器配置类中加了@Configuration注解导致重复注册bean,看了半天才看出来。

然后在spring.factories文件夹中加入配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yang.request.auth.configure.CloudRequestAuthAutoConfigure

其实这样就完成了,项目大致这个样子:

image-20230116102612815

然后用maven工具install下来,在微服务模块中使用测试一下:

引入依赖

<dependency>
    <groupId>com.yang.request.auth</groupId>
    <artifactId>gateway-request-auth-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency

application.yml中配置参数:

image-20230116102801565

这里参数要和gateway参数对应一致才行:

image-20230116102841369

然后启动网关模块和该服务模块,这里网关端口为8080,该微服务模块端口为9000:

经过网关模块的请求可以正常执行逻辑代码:

image-20230116103117324

直接访问微服务的请求被拦截:

image-20230116103205850

至此所有功能完成;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/183455.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用RadminLan和TcpRoute2将工作带回家

需要准备的工具 1.RadminLan 下载地址–>https://www.radmin-lan.cn/ 2.TcpRoute2 项目地址–>https://github.com/GameXG/TcpRoute2 *选用&#xff1a;浏览器插件proxy-switchyomega&#xff1a;https://microsoftedge.microsoft.com/addons/detail/proxy-switchyomega…

Visual Studio Code 的安装和使用

Visual Stuio Code 微软出的一款免费编辑器。 有 Windows、Linux 和macOS 三种版本的&#xff0c;属于跨平台的编辑器。它功能强大&#xff0c;支持插件工具安装&#xff0c;对于写代码、阅读代码的人来说是非常方便的。 1、安装 Visual Stuio Code 下载地址如下&#xff1a; h…

win10修改jdk版本之后不生效的有效解决方法

问题起因今天学习seata的时候&#xff0c;启动seata服务发现启动不了报下图错误。发现是自己jdk版本太高了&#xff0c;现在我用的是jdk17。然后我修改jdk的环境变量&#xff0c;确定保存好。发现jdk的版本还是没有变化。问题原因当使用安装版本的JDK程序时&#xff08;一般是1…

jmeter 并发测试

1.右键测试计划(Test plan), 添加线程组 2.线程组配置 3.右键线程组, 添加取样器-HTTP请求 4.HTTP请求配置 5. 添加查看结果树(也可以在Test plan 测试计划上右键添加)

Grafana 系列文章(二):使用 Grafana Agent 和 Grafana Tempo 进行 Tracing

&#x1f449;️URL: https://grafana.com/blog/2020/11/17/tracing-with-the-grafana-cloud-agent-and-grafana-tempo/ ✍Author: Robert Fratto • 17 Nov 2020 &#x1f4dd;Description: Heres your starter guide to configuring the Grafana Agent to collect traces and…

【刷题】多数元素

这是leetcode第169题的解答。 目录 一、多数元素 二、实现思路 1.排序中间下标求众数 2.投票法 总结 一、多数元素 多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 二、实现思路 1.排序中间下标求众数 原理&#xff1a; 通过排序使得数组有序&#xff0c;因为多数元素…

ESP32设备驱动-TM1637-驱动4位7段数码管

TM1637-驱动4位7段数码管 1、TM1637介绍 TM1637是一款带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成了MCU数字接口、数据锁存、LED高压驱动、键盘扫描等功能。 TM1637使用DIP20/SOP20封装,主要适用于电磁炉、微波炉、小家电的显示驱动。 TM1637有如下…

【C++】初识C++

本期博客我们来正式进入到期待已久C嘎嘎的学习希望C语言以后别给我打电话了&#xff0c;我怕C误会&#x1f63c;一、认识C1. 什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的 程序&#xff0c;需要高度的抽象和…

蓝奥声无线单火控制技术在单火开关应用中的优势

随着科技的发展&#xff0c;智能产品在生活中越来越常见&#xff0c;为方便业主使用&#xff0c;就连开关也有了高阶智能版&#xff0c;据相关专家介绍&#xff0c;智能开关主要分为单火和零火两种&#xff0c;很多非专业人士搞不明白&#xff0c;但又害怕因此选择失误。那么&a…

关于微服务的一些总结和经验之谈,来看看你都了解吗

文章目录一 谈谈对微服务的理解1. 什么微服务&#xff1f;2. 微服务体系3. 微服务优点4. 微服务缺点5. 什么是gRPC&#xff1f;6. ProtoBuf协议好处&#xff1f;7. gPRC和ProtoBuf联系&#xff1f;二 本次微服务项目学习流程梳理三 微服务项目一般开发流程梳理四 从本次微服务项…

数据结构 | 图结构的讲解与模拟实现 | DFS与BFS的实现

文章目录前言常见概念总结图的模拟实现邻接矩阵和邻接表的优劣图的模拟实现&#xff08;邻接表&#xff09;广度优先遍历&#xff08;BFS&#xff09;深度优先遍历&#xff08;DFS&#xff09;前言 在聊图的结构之前&#xff0c;我们可以先从熟悉的地方开始&#xff0c;这有一…

Leetcode 剑指 Offer II 012. 左右两边子数组的和相等

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 …

Android 启动速度优化

Android 启动速度优化前序统计adb测量手动打点方案预加载class字节码的预加载Activity预创建Glide预初始化WebView预加载数据预加载三方库初始化布局方面ViewStub标签减少层级主题的选择约束布局使用X2C方案过度绘制如何检测过度绘制如何监控页面的渲染速度移除多余背景Recycle…

Linux系列 Linux常用命令(2)

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.Linux常用命令后续 1.创建目录和文件 &#xff08;1&#x…

DaVinci:Camera Raw(Blackmagic RAW)

本文主要介绍 Blackmagic Raw 格式&#xff08;.braw&#xff09;素材相关的 Camera Raw 参数。解码质量Decode Quality解码质量决定了图像解拜耳之后所呈现的素质。默认为“使用项目设置” Use project setting&#xff0c;表示使用项目设置对话框中的“Camera RAW”解码质量设…

PPT录制视频的方法有哪些?分享5种亲测好用的方法

PPT文稿可以通过图文或者动画的形式&#xff0c;直观形象地把内容展现给观众&#xff0c;从而给观众留下深刻的印象。比如老师讲课时会用到PPT&#xff0c;公司开会时也会用到PPT。除了需要使用到PPT文稿之外&#xff0c;有时还要对它进行录制。那你知道PPT录制视频的方法有哪些…

[JavaWeb]HTML

目录1.简介1.1 HTML基本结构1.2 标签使用细节2.常用标签使用2.1 font 字体标签2.2 字符实体2.3 标题标签2.4 超链接标签2.5 有序无序标签(1)无序列表ul/li(2)有序列表ol/li2.6 图像标签(img)2.7 表格(table)标签表格标签-跨行跨列表格2.8 form(表单)标签介绍2.9 input单选多选标…

Unity-ROS与Navigation 2(四)

0. 简介 对于Gazebo而言&#xff0c;我们知道其是可以通过与ROS的连接完成机器人建图导航的&#xff0c;那我们是否可以通过Unity来完成相同的工作呢&#xff0c;答案是肯定的。这一讲我们就来讲述使用Unity的“Turtlebot3”模拟环境&#xff0c;来运行ROS2中的“Navigation 2…

Rust机器学习之tch-rs

Rust机器学习之tch-rs tch-rs是PyTorch接口的Rust绑定&#xff0c;可以认为tch-rs是Rust版的PyTorch。本文将带领大家学习如何用tch-rs搭建深度神经网络识别MNIST数据集中的手写数字。 本文是“Rust替代Python进行机器学习”系列文章的第五篇&#xff0c;其他教程请参考下面表…

autodeauth:一款功能强大的自动化Deauth渗透测试工具

关于autodeauth autodeauth是一款功能强大的自动化Deauth渗透测试工具&#xff0c;该工具可以帮助广大研究人员以自动化的形式针对本地网络执行Deauth渗透测试&#xff0c;或者枚举公共网络。当前版本的autodeauth已在树莓派OS和Kali Linux平台上进行过测试&#xff0c;之后的…