当前位置: 首页 > news >正文

【第14章】Spring Cloud之Gateway路由断言(IP黑名单)

文章目录

  • 前言
  • 一、内置路由断言
    • 1. 案例(Weight)
    • 2. 更多断言
  • 二、自定义路由断言
    • 1. 黑名单断言
    • 2. 全局异常处理
    • 3. 应用配置
    • 4. 单元测试
  • 总结


前言

Spring Cloud Gateway可以让我们根据请求内容精确匹配到对应路由服务,官方已经内置了很多路由断言,我们也可以根据需求自己定义,RemoteAddrRoutePredicateFactory就像是根据IP去匹配的白名单,接下来我们根据它来自定义一个IP黑名单。


一、内置路由断言

1. 案例(Weight)

spring:cloud:gateway:routes:- id: weight_highuri: https://weighthigh.orgpredicates:- Weight=group1, 8- id: weight_lowuri: https://weightlow.orgpredicates:- Weight=group1, 2

这条路线将把约80%的流量转发到weighthigh.org,约20%的流量转发给weighlow.org

2. 更多断言

序号断言类型用法描述
1After- After=2017-01-20T17:42:47.789-07:00[America/Denver]此路由与2017年1月20日17:42:47之后的任何请求相匹配。
2Before- Before=2017-01-20T17:42:47.789-07:00[America/Denver]此路由与2017年1月20日17:42:47之前的任何请求相匹配。
3Between- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]此路由与2017年1月20日17:42:47之后至2017年1月21日17:42:47之前提出的任何请求相匹配。
4Cookie- Cookie=chocolate, ch.p此路由匹配名为chocolate的cookie的请求,该cookie的值与ch.p匹配。
5Header- Header=X-Request-Id, \d+此路由匹配请求有一个名为X-request-Id的请求头,其值与\d+正则表达式匹配(即它有一个或多个数字的值)。
6Host- Host=.somehost.org,.anotherhost.org此路由匹配请求的Host值为www.somehost.org、beta.somehost.org或www.anotherhost.org。
7Method- Method=GET,POST此路由匹配请求方法是GET或POST。
8Path- Path=/red/{segment},/blue/{segment}此路由匹配请求路径为:/red/1 或 /red/1/ 或 /red/blue 或/blue/green。
9Query- Query=green- Query=green - Query=red, gree.
10RemoteAddr- RemoteAddr=192.168.1.1/24如果请求的远程地址是192.168.1.10,则此路由匹配。
11XForwarded Remote Addr- XForwardedRemoteAddr=192.168.1.1/24如果X-Forwarded-For标头包含例如192.168.1.10,则此路由匹配。

二、自定义路由断言

1. 黑名单断言

package org.example.gateway.predicate;import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ipfilter.IpSubnetFilterRule;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.cloud.gateway.support.ipresolver.RemoteAddressResolver;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import static org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType.GATHER_LIST;/*** Create by zjg on 2024/7/29*/
@Component
public class BlackRemoteAddrRoutePredicateFactory  extends AbstractRoutePredicateFactory<BlackRemoteAddrRoutePredicateFactory.Config> {private static final Log log = LogFactory.getLog(BlackRemoteAddrRoutePredicateFactory.class);public BlackRemoteAddrRoutePredicateFactory() {super(BlackRemoteAddrRoutePredicateFactory.Config.class);}@Overridepublic ShortcutType shortcutType() {return GATHER_LIST;}@Overridepublic List<String> shortcutFieldOrder() {return Collections.singletonList("sources");}@NotNullprivate List<IpSubnetFilterRule> convert(List<String> values) {List<IpSubnetFilterRule> sources = new ArrayList<>();for (String arg : values) {addSource(sources, arg);}return sources;}@Overridepublic Predicate<ServerWebExchange> apply(BlackRemoteAddrRoutePredicateFactory.Config config) {List<IpSubnetFilterRule> sources = convert(config.sources);return new GatewayPredicate() {@Overridepublic boolean test(ServerWebExchange exchange) {InetSocketAddress remoteAddress = config.remoteAddressResolver.resolve(exchange);if (remoteAddress != null && remoteAddress.getAddress() != null) {String hostAddress = remoteAddress.getAddress().getHostAddress();String host = exchange.getRequest().getURI().getHost();if (log.isDebugEnabled() && !hostAddress.equals(host)) {log.debug("Black remote addresses didn't match " + hostAddress + " != " + host);}for (IpSubnetFilterRule source : sources) {if (source.matches(remoteAddress)) {exchange.getAttributes().put("BlackRemoteAddrRoutePredicateFactory",remoteAddress.getAddress().getHostAddress());return false;//能匹配到则在黑名单中,不再执行}}}return true;}@Overridepublic Object getConfig() {return config;}@Overridepublic String toString() {return String.format("BlackRemoteAddrs: %s", config.getSources());}};}private void addSource(List<IpSubnetFilterRule> sources, String source) {if (!source.contains("/")) { // no netmask, add defaultsource = source + "/32";}String[] ipAddressCidrPrefix = source.split("/", 2);String ipAddress = ipAddressCidrPrefix[0];int cidrPrefix = Integer.parseInt(ipAddressCidrPrefix[1]);sources.add(new IpSubnetFilterRule(ipAddress, cidrPrefix, IpFilterRuleType.ACCEPT));}@Validatedpublic static class Config {@NotEmptyprivate List<String> sources = new ArrayList<>();@NotNullprivate RemoteAddressResolver remoteAddressResolver = new RemoteAddressResolver() {};public List<String> getSources() {return sources;}public BlackRemoteAddrRoutePredicateFactory.Config setSources(List<String> sources) {this.sources = sources;return this;}public BlackRemoteAddrRoutePredicateFactory.Config setSources(String... sources) {this.sources = Arrays.asList(sources);return this;}public BlackRemoteAddrRoutePredicateFactory.Config setRemoteAddressResolver(RemoteAddressResolver remoteAddressResolver) {this.remoteAddressResolver = remoteAddressResolver;return this;}}
}

2. 全局异常处理

package org.example.gateway.config;import org.example.common.model.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.reactive.resource.NoResourceFoundException;
import org.springframework.web.server.ServerWebExchange;
import java.io.PrintWriter;
import java.io.StringWriter;/*** Create by zjg on 2024/7/29*/
@RestControllerAdvice
public class GlobalExceptionHandler {Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);@ExceptionHandler(NoResourceFoundException.class)//无可用路由public Result exception(ServerWebExchange exchange, NoResourceFoundException ex){String detail = ex.getBody().getDetail();String mark="resource ";String message = detail.substring(detail.indexOf(mark) + mark.length());setStatusCode(exchange.getResponse(),ex.getStatusCode());if(StringUtils.hasText(exchange.getAttribute("BlackRemoteAddrRoutePredicateFactory"))){//IP黑名单return  Result.error(ex.getStatusCode().value(),"拒绝访问","您的IP已被添加到黑名单中,拒绝访问!");}return  Result.error(ex.getStatusCode().value(),"无可用路由",String.format("没有可用的路由[%s]",message));}@ExceptionHandler(NotFoundException.class)//无可用服务public Result exception(ServerHttpResponse response,NotFoundException ex){logger.error(ex.getMessage());String detail = ex.getBody().getDetail();String mark="for ";String message = detail.substring(detail.indexOf(mark) + mark.length());setStatusCode(response,ex.getStatusCode());return  Result.error(ex.getStatusCode().value(),"服务不可用",String.format("没有可用的服务实例[%s]",message));}@ExceptionHandler(Exception.class)//异常保底public Result exception(ServerHttpResponse response,Exception exception){StringWriter stringWriter = new StringWriter();PrintWriter writer=new PrintWriter(stringWriter);exception.printStackTrace(writer);logger.error(stringWriter.toString());setStatusCode(response,HttpStatus.INTERNAL_SERVER_ERROR);return  Result.error(HttpStatus.INTERNAL_SERVER_ERROR.value(),exception.getMessage());}private void setStatusCode(ServerHttpResponse response,HttpStatusCode httpStatusCode){response.setStatusCode(httpStatusCode);}
}

3. 应用配置

spring:cloud:gateway:routes:- id: provider-serviceuri: lb://provider-servicepredicates:- Path=/provider/**- BlackRemoteAddr=192.168.1.1/24,127.0.0.1

4. 单元测试

curl 192.168.0.104:8888/provider/hello

正常访问
在这里插入图片描述

黑名单访问
在这里插入图片描述


总结

回到顶部

这样我们就能通过断言配置黑名单,可以针对固定IP做灵活处理。

相关文章:

【第14章】Spring Cloud之Gateway路由断言(IP黑名单)

文章目录 前言一、内置路由断言1. 案例&#xff08;Weight&#xff09;2. 更多断言 二、自定义路由断言1. 黑名单断言2. 全局异常处理3. 应用配置4. 单元测试 总结 前言 Spring Cloud Gateway可以让我们根据请求内容精确匹配到对应路由服务,官方已经内置了很多路由断言,我们也…...

3、pnpm yarn npm

项目里实际上就只有这些依赖 node module 里却有很多的包 原因&#xff1a; 比如说vue&#xff0c;vue内部有依赖了其余的包。工具又依赖了别的依赖 造成的问题&#xff1a;我可以直接去用这个包&#xff0c;但是这个包在package.json中却没有看到-----幽灵依赖 那如果说别…...

❄️5. Kubernetes核心资源之名称空间和Pod实战

**什么是名称空间Namespace: ** Namespace是k8s系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多用户的资源隔离。默认情况下&#xff0c;k8s集群中的所有的Pod都是可以相互访问的。但是在实际中&#xff0c;可能不想让两个Pod之间进行互…...

锂电池充电板电路设计

写这篇文章的目的主要是个人经验的总结&#xff0c;希望能给开发者们提供一种锂电池充电电路以及电源显示的电路思路。接下来从以下几个方面讲述电路。 设计这款电路的初衷是想用一块硬币大小的锂电池作为供电电源&#xff08;3.5V-4.2V&#xff09;&#xff0c;降压供给3.3V电…...

工业互联网产教融合实训基地解决方案

一、引言 随着“中国制造2025”战略的深入实施与全球工业4.0浪潮的兴起&#xff0c;工业互联网作为新一代信息技术与制造业深度融合的产物&#xff0c;正引领着制造业向智能化、网络化、服务化转型。为培养适应未来工业发展需求的高素质技术技能人才&#xff0c;构建工业互联网…...

高效批量提取PPT幻灯片中图片的方法

处理包含大量图片的PPT&#xff08;PowerPoint&#xff09;幻灯片已成为许多专业人士的日常任务之一。然而&#xff0c;手动从每张幻灯片中逐一提取图片不仅耗时耗力&#xff0c;还容易出错。为了提升工作效率&#xff0c;减少重复劳动&#xff0c;探索并实现一种高效批量提取P…...

怎么在 React Native 应用中处理深度链接?

深度链接是一种技术&#xff0c;其中给定的 URL 或资源用于在移动设备上打开特定页面或屏幕。因此&#xff0c;深度链接可以引导用户到应用程序内的特定屏幕&#xff0c;而不仅仅是启动移动设备上的应用程序&#xff0c;从而提供更好的用户体验。这个特定的屏幕可能位于一系列层…...

el-table自动滚动到最底部

我的需求是这样的&#xff0c;因为我的表格是动态的&#xff0c;可以手动新增行&#xff0c;固定表头&#xff0c;而且需要一屏显示&#xff0c;为了方便用户就需要再新增的时候表格自动向上滚动。 差了官方文档后发现有一个属性可以支持 这个属性正是自己需要的&#xff0c;所…...

小白零基础学数学建模系列-引言与课程目录

目录 引言一、我们的专辑包含哪些内容&#xff1f;第一周&#xff1a;数学建模基础与工具第二周&#xff1a;高级数学建模技巧与应用第三周&#xff1a;机器学习基础与数据处理第四周&#xff1a;监督学习与无监督学习算法第五周&#xff1a;神经网络 二、学完本专辑能收获到什…...

Integer类型比较是 == 还是equals()

在Java编程中&#xff0c;判断两个Integer对象是否相等时&#xff0c;我们经常遇到使用和equals()方法的选择问题。这两个操作符和方法在判断对象相等性时有所不同&#xff0c;理解它们的区别对于编写健壮的代码至关重要。 使用判断Integer相等性 在Java中&#xff0c;操作符…...

七夕情人节送什么礼物?看完这篇你就知道了

在这个充满爱意的时刻&#xff0c;送上一份精心挑选的礼物&#xff0c;不仅能表达你的爱意&#xff0c;更能加深彼此之间的情感联系。然而&#xff0c;选择一份合适的情人节礼物并非易事&#xff0c;因为每个人都有其独特的需求和喜好。如果你还在为情人节送什么礼物而纠结&…...

让B站直接变成一个纯粹的音乐平台的简单小方法

可能在大多数人眼里&#xff0c;B站就是一个内容丰富的高质量视频平台 但实际上B站还是一个“音乐平台”&#xff0c;只不过大多数时候都是以视频的形式呈现&#xff0c;所以你们可能对此没啥感觉。 那么今天给大家分享一款神级插件&#xff0c;让B站变成一个纯粹的音乐平台&a…...

【MySQL 01】在 Ubuntu 22.04 环境下安装 MySQL

文章目录 &#x1f308; 1. 说明&#x1f308; 2. 卸载不必要的环境&#x1f308; 3. 安装 MySQL&#x1f308; 4. 启动和关闭 MySQL 服务&#x1f308; 5. 临时登录 MySQL&#x1f308; 6. 设置 MySQL 密码&#x1f308; 7. 配置 MySQL &#x1f308; 1. 说明 在安装与卸载中…...

linux命令 根据某一字段去掉txt中重复的数据

前提&#xff1a; 文档为格式化好的数据。比如一行是一个json。 判断总共有多少行数据&#xff1a; grep No f.txt | wc -l 查询重复数据有多少行&#xff1a; grep No f.txt | sort -u | wc -l 找到重复的那行数据&#xff1a;(如果每行的json数据大&#xff0c;可忽略此操…...

LVS(Linux virual server)

一&#xff1a;环境准备&#xff1a; rhel9 软件&#xff1a;httpd&#xff0c; ipvsadm 四台纯净的rhel9机子&#xff1a;一台LVS调度设备&#xff08;双网卡&#xff09;&#xff0c;两台webserver&#xff08;单网卡仅主机&#xff09;&#xff0c;一台客户机 DR模式多…...

End-to-End Object Detection with Transformers(Detection Transformer)翻译

摘要 我们提出了一种新方法&#xff0c;将目标检测视为直接的集合预测问题。我们的方法简化了检测流程&#xff0c;有效消除了对许多手工设计组件的需求&#xff0c;如非极大值抑制过程或锚框生成&#xff0c;这些组件显式编码了我们对任务的先验知识。新框架称为检测变换器&a…...

uniapp打开地图直接获取位置

uniapp官网文档 https://en.uniapp.dcloud.io/api/location/open-location.html <view class"map-content" click.stop"kilometer(item)"><view class"km">{{item.distance||0}}km</view></view>import map from ../../…...

Qt的事件处理机制、信号和槽以及两者之间的区别

Qt的事件处理机制 Qt 的事件处理机制是其框架的核心部分之一&#xff0c;用于处理用户操作、系统事件以及其他各种事件。以下是 Qt 事件处理机制的关键组成部分和流程&#xff1a; 事件对象 (QEvent)&#xff1a; 所有事件在 Qt 中都是通过事件对象来表示的。QEvent 是所有事…...

LSTM实战之预测股票

&#x1f4c8; 用PyTorch搭建LSTM模型&#xff0c;轻松预测股票价格&#xff01;&#x1f680; Hey小伙伴们&#xff0c;今天给大家带来一个超级实用的项目教程——如何用PyTorch和LSTM模型来预测股票价格&#xff01;&#x1f31f; &#x1f50d; 项目背景 我们都知道股市是…...

30-50K|抖音大模型|社招3轮面经

情况介绍&#xff1a;我主要做nlp&#xff0c;也涉及到多模态和强化学习。现在大环境比较差&#xff0c;能投的公司不是很多&#xff0c;比如腾讯&#xff0c;主要还是高级别的&#xff0c;所以腾讯我就没投 抖音一面 1、聊项目。 2、AUC的两种公式是&#xff1f;你能证明这…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...