Nacos实现IP动态黑白名单过滤

一些恶意用户(可能是黑客、爬虫、DDoS 攻击者)可能频繁请求服务器资源,导致资源占用过高。因此我们需要一定的手段实时阻止可疑或恶意的用户,减少攻击风险。
 

本次练习使用到的是Nacos配合布隆过滤器实现动态IP黑白名单过滤

文章目录

目录

文章目录

一、IP黑白名单是什么?

二、使用步骤

1.使用Nacos

1.通过Nacos添加配置

2.引入依赖

2.使用

1.定义一个获取IP的方法

2.创建黑名单过滤工具类

3.创建Nacos配置监听类

4.创建黑白名单过滤器

总结


一、IP黑白名单是什么?

一些恶意用户(可能是黑客、爬虫、DDoS 攻击者)可能频繁请求服务器资源,导致资源占用过高。因此我们需要一定的手段实时阻止可疑或恶意的用户,减少攻击风险。

通过 IP 封禁,可以有效拉黑攻击者,防止资源被滥用,保障合法用户的正常访问。

对于我们的需求,不让拉进黑名单的 IP 访问任何接口。

二、使用步骤

1.使用Nacos

首先就是下载Nacos

通过网盘分享的文件:nacos
链接: https://pan.baidu.com/s/12-9UA6hUSlEeyuKVfNPkJw?pwd=fr2z 提取码: fr2z 
--来自百度网盘超级会员v6的分享

拿到文件夹内容是

 打开bin目录

//运行命令行
startup.sh -m standalone

 

 看到这个界面就代表着Nacos运行成功了

1.通过Nacos添加配置

访问:http://127.0.0.1:8848/nacos ,默认用户名和密码都是 nacos

此时创建自己的配置

 

 之后选择发布

2.引入依赖

<dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>0.2.12</version>
</dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.8</version></dependency>

 在application.yml中添加依赖

# 配置中心
nacos:config:server-addr: 127.0.0.1:8848  # nacos 地址bootstrap:enable: true  # 预加载data-id: 这里填写上面你在配置文件里面填写的Data ID # 控制台填写的 Data IDgroup: DEFAULT_GROUP # 控制台填写的 grouptype: yaml  # 选择的文件格式auto-refresh: true # 开启自动刷新

2.使用

1.定义一个获取IP的方法

package com.hhh.mianshiya.utils;import java.net.InetAddress;
import javax.servlet.http.HttpServletRequest;/*** 网络工具类** @author <a href="https://github.com/liyupi">程序员鱼皮</a>* @from <a href="https://yupi.icu">编程导航知识星球</a>*/
public class NetUtils {/*** 获取客户端 IP 地址** @param request* @return*/public static String getIpAddress(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();if (ip.equals("127.0.0.1")) {// 根据网卡取本机配置的 IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (Exception e) {e.printStackTrace();}if (inet != null) {ip = inet.getHostAddress();}}}// 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ip != null && ip.length() > 15) {if (ip.indexOf(",") > 0) {ip = ip.substring(0, ip.indexOf(","));}}if (ip == null) {return "127.0.0.1";}return ip;}}

2.创建黑名单过滤工具类

package com.hhh.mianshiya.blackfilter;import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.yaml.snakeyaml.Yaml;import java.util.Collections;
import java.util.List;
import java.util.Map;@Slf4j
public class BlackIpUtils {// 声明一个静态的、线程安全的布隆过滤器实例private static volatile BitMapBloomFilter bloomFilter;/*** 判断 IP 是否在黑名单中* * @param ip 待检查的 IP 地址* @return 如果 IP 地址在黑名单中,则返回 true;否则返回 false*/public static boolean isBlackIp(String ip) {// 防御性编程,防止 bloomFilter 未初始化时调用if (bloomFilter == null) {log.warn("Bloom filter is not initialized. Returning false for IP: {}", ip);return false;}return bloomFilter.contains(ip);}/*** 重建黑名单布隆过滤器* * @param configInfo 包含黑名单配置信息的字符串*/public static void rebuildBlackIp(String configInfo) {// 处理空或无效的配置信息if (StrUtil.isBlank(configInfo)) {log.warn("你没有传递配置文件的内容");configInfo = "{}";}try {// 解析 Yaml 文件Yaml yaml = new Yaml();Map<String, Object> map = yaml.loadAs(configInfo, Map.class);// 获取黑名单列表List<String> blackIpList = (List<String>) map.getOrDefault("blackIpList", Collections.emptyList());synchronized (BlackIpUtils.class) {// 构建布隆过滤器BitMapBloomFilter bitMapBloomFilter = new BitMapBloomFilter(Math.max(blackIpList.size(), 100)); // 设置合理的默认容量// 填充黑名单 IPfor (String ip : blackIpList) {bitMapBloomFilter.add(ip);}// 替换静态布隆过滤器bloomFilter = bitMapBloomFilter;log.info("Bloom filter rebuilt successfully with {} IPs.", blackIpList.size());}} catch (Exception e) {log.error("Failed to rebuild Bloom filter. Config info: {}", configInfo, e);// 如果发生异常,使用一个默认空的布隆过滤器synchronized (BlackIpUtils.class) {bloomFilter = new BitMapBloomFilter(100);}}}
}

3.创建Nacos配置监听类

在 blackfilter 包中新增监听器代码,追求性能的话可以自定义线程池

package com.hhh.mianshiya.blackfilter;import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.validation.constraints.NotNull;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;// 使用slf4j日志框架记录日志信息
@Slf4j
// 标识该类为Spring框架的组件,自动注入到Spring容器中
@Component
public class NacosListener implements InitializingBean {// 注入Nacos配置服务@NacosInjectedprivate ConfigService configService;// 从配置中获取Nacos数据ID@Value("${nacos.config.data-id}")private String dataId;// 从配置中获取Nacos分组信息@Value("${nacos.config.group}")private String group;// 实现InitializingBean接口,当所有属性设置完毕后调用此方法@Overridepublic void afterPropertiesSet() throws Exception {// 记录日志:nacos监听器启动log.info("nacos 监听器启动");// 从Nacos中获取配置信息,并添加配置变更监听器String config = configService.getConfigAndSignListener(dataId, group, 3000L, new Listener() {// 创建线程工厂,用于生成线程池中的线程final ThreadFactory threadFactory = new ThreadFactory() {// 用于生成线程池编号private final AtomicInteger poolNumber = new AtomicInteger(1);// 创建并配置线程@Overridepublic Thread newThread(@NotNull Runnable r) {Thread thread = new Thread(r);// 设置线程名称thread.setName("refresh-ThreadPool" + poolNumber.getAndIncrement());return thread;}};// 创建固定大小的线程池,用于异步处理配置变更事件final ExecutorService executorService = Executors.newFixedThreadPool(1, threadFactory);// 通过线程池异步处理黑名单变化的逻辑@Overridepublic Executor getExecutor() {return executorService;}// 监听后续黑名单变化@Overridepublic void receiveConfigInfo(String configInfo) {// 记录日志:监听到配置信息变化log.info("监听到配置信息变化:{}", configInfo);// 调用工具类方法,根据新的配置信息更新黑名单BlackIpUtils.rebuildBlackIp(configInfo);}});// 初始化黑名单BlackIpUtils.rebuildBlackIp(config);}
}

4.创建黑白名单过滤器

@WebFilter(urlPatterns = "/*", filterName = "blackIpFilter")
public class BlackIpFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {String ipAddress = NetUtils.getIpAddress((HttpServletRequest) servletRequest);if (BlackIpUtils.isBlackIp(ipAddress)) {servletResponse.setContentType("text/json;charset=UTF-8");servletResponse.getWriter().write("{\"errorCode\":\"-1\",\"errorMsg\":\"黑名单IP,禁止访问\"}");return;}filterChain.doFilter(servletRequest, servletResponse);}}

此时添加上这个过滤器之后需要在主类上面添加注解

@ServletComponentScan

此时访问接口


总结

今天看了鱼皮的项目,第一次接触到了这种商业性质的思路,颇有感触,特写下博客记录

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

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

相关文章

vue-next-admin框架配置(vue)

vue-next-admin 先安装依赖 npm i 依赖, npm run dev 运行 1.配置代理 2.把他的逻辑和自己的登录判断逻辑结合(我的放下面&#xff0c;可以参考哦&#xff0c;可以直接使用&#xff0c;到时候修改登录逻辑就好)&#xff0c;别忘了引入ajxio哦 const onSignIn async () &g…

算法定制LiteAIServer视频智能分析平台工业排污检测算法智控环保监管

随着工业化进程的加快&#xff0c;环境污染问题愈加严重&#xff0c;尤其是工业排污对生态环境的影响引发了广泛关注。在此背景下&#xff0c;视频智能分析平台LiteAIServer工业排污检测算法应运而生&#xff0c;作为一种先进的智能化解决方案&#xff0c;它在监测和管理工业排…

mini-lsm通关笔记Week2Day5

项目地址&#xff1a;https://github.com/skyzh/mini-lsm 个人实现地址&#xff1a;https://gitee.com/cnyuyang/mini-lsm Summary 在本章中&#xff0c;您将&#xff1a; 实现manifest文件的编解码。系统重启时从manifest文件中恢复。 要将测试用例复制到启动器代码中并运行…

【WPF】Prism学习(六)

Prism Dependency Injection 1.依赖注入&#xff08;Dependency Injection&#xff09; 1.1. Prism与依赖注入的关系&#xff1a; Prism框架一直围绕依赖注入构建&#xff0c;这有助于构建可维护和可测试的应用程序&#xff0c;并减少或消除对静态和循环引用的依赖。 1.2. P…

学习ASP.NET Core的身份认证(基于Cookie的身份认证1)

B/S架构程序可通过Cookie、Session、JWT、证书等多种方式认证用户身份&#xff0c;虽然之前测试过用户登录代码&#xff0c;也学习过开源项目中的登录认证&#xff0c;但其实还是对身份认证疑惑甚多&#xff0c;就比如登录验证后用户信息如何保存、客户端下次连接时如何获取用户…

使用Cursor和Claude AI打造你的第一个App

大家好&#xff0c;使用Cursor和Claude AI打造应用程序是一个结合智能代码辅助和人工智能对话的创新过程。Cursor是一个编程辅助工具&#xff0c;它通过智能代码补全、聊天式AI对话和代码生成等功能&#xff0c;帮助开发者提高编程效率。Claude AI则是一个强大的人工智能平台&a…

ssm152家庭财务管理系统设计与实现+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;家庭财务管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本家庭财务管理系…

《深入理解 Spring MVC 工作流程》

一、Spring MVC 架构概述 Spring MVC 是一个基于 Java 的轻量级 Web 应用框架&#xff0c;它遵循了经典的 MVC&#xff08;Model-View-Controller&#xff09;设计模式&#xff0c;将请求、响应和业务逻辑分离&#xff0c;从而构建出灵活可维护的 Web 应用程序。 在 Spring MV…

LeetCode - #139 单词拆分

文章目录 前言摘要1. 描述2. 示例3. 答案题解动态规划的思路代码实现代码解析1. **将 wordDict 转换为 Set**2. **初始化 DP 数组**3. **状态转移方程**4. **返回结果** **测试用例**示例 1:示例 2:示例 3: 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗…

LLM( Large Language Models)典型应用介绍 1 -ChatGPT Large language models

ChatGPT 是基于大型语言模型&#xff08;LLM&#xff09;的人工智能应用。 GPT 全称是Generative Pre-trained Transformer。-- 生成式预训练变换模型&#xff1a; Generative&#xff08;生成式&#xff09;&#xff1a;可以根据输入生成新的文本内容&#xff0c;例如回答问题…

维护在线重做日志

学习目标 解释在线重做日志文件的目的概述在线重做日志文件的结构控制日志开关和检查点多路复用和维护在线重做日志文件使用OMF管理在线重做日志文件获取在线重做日志文件信息 在线重做日志文件提供了在数据库发生故障时重做事务的方法。 每个事务都同步写入重做日志缓冲区&a…

分布式数据库中间件可以用在哪些场景呢

在数字化转型的浪潮中&#xff0c;企业面临着海量数据的存储、管理和分析挑战。华为云分布式数据库中间件&#xff08;DDM&#xff09;作为一款高效的数据管理解决方案&#xff0c;致力于帮助企业在多个场景中实现数据的高效管理和应用&#xff0c;提升业务效率和用户体验。九河…

shell(6)if条件判断与for循环结构

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

vulfocus在线靶场:tomcat-pass-getshell 弱口令 速通手册

目录 一、启动环境&#xff0c;访问页面&#xff0c;并登录&#xff0c;账号密码都是tomcat 二、哥斯拉打war包&#xff0c;图解 三、上传war包&#xff0c;图解 四、访问我们直接url/木马文件名/木马文件.jsp&#xff0c;是否存在了 五、 哥斯拉测试连接结果success&…

DICOM核心概念:显式 VR(Explicit VR)与隐式 VR(Implicit VR)在DICOM中的定义与区别

在DICOM&#xff08;Digital Imaging and Communications in Medicine&#xff09;标准中&#xff0c;VR&#xff08;Value Representation&#xff09; 表示数据元素的值的类型和格式。理解显式 VR&#xff08;Explicit VR&#xff09;与隐式 VR&#xff08;Implicit VR&#…

2、桥接模式

模式解释 百度&#xff1a; 这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的交流调用。这种模式涉及到一个作为桥接的接口&#xff0c;使得实体类的功能独立于接口实现类&#xff0c;这两种类型的类可被结构化…

小程序-基于java+SpringBoot+Vue的开放实验室预约管理系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

【JavaSE】【网络编程】UDP数据报套接字编程

目录 一、网络编程简介二、Socket套接字三、TCP/UDP简介3.1 有连接 vs 无连接3.2 可靠传输 vs 不可靠传输3.3 面向字节流 vs 面向数据报3.4 双向工 vs 单行工 四、UDP数据报套接字编程4.1 API介绍4.1.1 DatagramSocket类4.1.1.1 构造方法4.1.1.2 主要方法 4.1.2 DatagramPocket…

【K8S系列】Kubernetes Pod节点ImagePullBackOff 状态及解决方案详解【已解决】

在 Kubernetes 中&#xff0c;当某个 Pod 的容器无法从指定的镜像仓库拉取镜像时&#xff0c;Pod 的状态会变为 ImagePullBackOff。这通常是因为指定的镜像不存在、镜像标签错误、认证失败或网络问题等原因。 以下是关于 ImagePullBackOff 的详细分析及解决方案。 1. ImagePull…