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 ID
    group: DEFAULT_GROUP # 控制台填写的 group
    type: 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")) {
                // 根据网卡取本机配置的 IP
                InetAddress 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)); // 设置合理的默认容量
    
                // 填充黑名单 IP
                for (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配置服务
    @NacosInjected
    private ConfigService configService;

    // 从配置中获取Nacos数据ID
    @Value("${nacos.config.data-id}")
    private String dataId;

    // 从配置中获取Nacos分组信息
    @Value("${nacos.config.group}")
    private String group;

    // 实现InitializingBean接口,当所有属性设置完毕后调用此方法
    @Override
    public 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);

                // 创建并配置线程
                @Override
                public 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);

            // 通过线程池异步处理黑名单变化的逻辑
            @Override
            public Executor getExecutor() {
                return executorService;
            }

            // 监听后续黑名单变化
            @Override
            public void receiveConfigInfo(String configInfo) {
                // 记录日志:监听到配置信息变化
                log.info("监听到配置信息变化:{}", configInfo);
                // 调用工具类方法,根据新的配置信息更新黑名单
                BlackIpUtils.rebuildBlackIp(configInfo);
            }
        });
        // 初始化黑名单
        BlackIpUtils.rebuildBlackIp(config);
    }
}

4.创建黑白名单过滤器

@WebFilter(urlPatterns = "/*", filterName = "blackIpFilter")
public class BlackIpFilter implements Filter {

    @Override
    public 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

此时访问接口


总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32芯片EXIT外部中断的配置与原理以及模板代码(标准库)

配置EXIT外部中断其实就是把GPIO刀NVIC的各个外设配置好 第一步&#xff1a;配置RCC&#xff0c;把我们涉及到的外设的时钟都打开 &#xff08;此处EXTI是默认打开的&#xff0c;而NVIC是内核外设无需配置&#xff09; 第二步&#xff1a;配置GPIO,选择端口为输入模式 第三…

大数据实验4-HBase

一、实验目的 阐述HBase在Hadoop体系结构中的角色&#xff1b;能够掌握HBase的安装和配置方法熟练使用HBase操作常用的Shell命令&#xff1b; 二、实验要求 学习HBase的安装步骤&#xff0c;并掌握HBase的基本操作命令的使用&#xff1b; 三、实验平台 操作系统&#xff1…

商用密码产品认证名录说明

《商用密码产品认证目录》是为贯彻落实《中华人民共和国密码法》&#xff0c;进一步健全完善商用密码产品认证体系&#xff0c;更好满足商用密码产业发展需要&#xff0c;根据《国家密码管理局 市场监管总局关于调整商用密码产品管理方式的公告》《市场监管总局 国家密码管理局…

uniapp微信小程序接入airkiss插件进行WIFI配网

本文可参考uniapp小程序插件 一.申请插件 微信公众平台设置页链接&#xff1a;微信公众平台 登录您的小程序微信公众平台&#xff0c;进入设置页&#xff0c;在第三方设置->插件管理->添加插件中申请AiThinkerAirkissforWXMini插件&#xff0c;申请的插件appId为【wx6…

突破自动驾驶瓶颈!KoMA:多智能体与大模型的完美融合

0.简介 本推文主要介绍了由来自北京航空航天大学的姜克谋、蔡轩和崔智勇教授等共同提出的一种名为KoMA的知识驱动的多智能体框架。论文《KoMA: Knowledge-driven Multi-agent Framework for Autonomous Driving with Large Language Models》提出了KoMA框架&#xff0c;通过结…

企业项目级IDEA编辑器设置类注释、方法注释模板(仅增加@author和@date)

文章目录 前言一 设置类注释1.1 添加模板1.2 复制配置 二 设置方法注释2.1 添加模版2.2 设置模版2.3 设置参数变量2.4 配置对应快捷键2.5 配置对应作用域2.6 使用方式 说明 前言 公司代码规范中&#xff0c;需要在标准JavaDoc注释的基础上加上作者和日期。网上虽然有很多现成的…

【HOT100第五天】搜索二维矩阵 II,相交链表,反转链表,回文链表

240.搜索二维矩阵 II 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 先动手写写最简单方法&#xff0c;二重循环。 class Solution { public:bool searchMa…

OLED透明屏在零售行业有哪些优势

OLED透明屏在零售行业具有诸多优势&#xff0c;这些优势使得它成为零售行业中一种创新且高效的展示工具。以下是对OLED透明屏在零售行业优势的详细分析&#xff1a; 1. 视觉吸引力与沉浸感 高透明度&#xff1a;OLED透明屏能够实现40%以上的透明度&#xff0c;使得屏幕后的物体…

kali搭建pikachu靶场

前言&#xff1a; 总所周知搭个网站需要有apachemysqlphp&#xff0c;Apache是一个开源的Web服务器软件&#xff0c; MySQL是一种关系型数据库管理系统&#xff08;数据库&#xff09;&#xff0c;PHP是一种在服务器上执行的脚本语言 文章内容来自&#xff1a;【黑帽编程与攻…

学习threejs,对模型多个动画切换展示

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.AnimationMixer 动画…

【再谈设计模式】适配器模式 ~接口兼容的桥梁

一、引言 在软件开发的复杂世界里&#xff0c;不同的组件、类或者系统往往有着各自独立的设计和接口定义。当需要将这些原本不兼容的部分整合在一起协同工作时&#xff0c;就像尝试将方形的榫头插入圆形的卯眼一样困难。适配器设计模式就如同一位神奇的工匠&#xff0c;能够巧妙…

光猫、路由器、交换机之连接使用(Connection and Usage of Optical Cats, Routers, and Switches)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…

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

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

【Python小技巧】高效实现文件批量重命名

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

ES分词环境实战

文章目录 安装下载1.1 下载镜像1.2 单节点启动 防火墙设置异常处理【1】iptable链路中断 参考文档 参加完2024年11月软考&#xff0c;对ES的分词进行考查&#xff0c;前期有【 Docker 环境下安装部署 Elasticsearch 和 kibana】和【 Docker 环境下为 Elasticsearch 安装IK 分…

华为云stack网络服务流量走向

1.同VPC同子网同主机内ECS间互访流量走向 一句话通过主机内部br-int通信 2.同VPC同子网跨主机ECS间互访流量走向 3.同VPC不同子网同主机ECS间互访流量走向 去往本机的mac地址都记录在br-tun流表里 4.同VPC不同子网跨主机ECS间互访流量走向 5.对等连接流量走向&#xff08;跨V…

计算机网络:运输层 —— TCP 的拥塞控制

文章目录 TCP的拥塞控制拥塞控制的基本方法流量控制与拥塞控制的区别拥塞控制分类闭环拥塞控制算法 TCP的四种拥塞控制方法&#xff08;算法&#xff09;窗口慢开始门限慢开始算法拥塞避免算法快重传算法快恢复算法 TCP拥塞控制的流程TCP拥塞控制与网际层拥塞控制的关系 TCP的拥…

利用uniapp开发鸿蒙:运行到鸿蒙模拟器—踩坑合集

从uniapp运行到鸿蒙模拟器上这一步&#xff0c;就有非常多的坑&#xff0c;一些常见的坑&#xff0c;官网都有介绍&#xff0c;就不再拿出来了&#xff0c;这里记录一下官网未记录的大坑 1.运行路径从hbuilderx启动鸿蒙模拟器 解决方法&#xff1a; Windows系统&#xff0c;官…

linux 常用命令指南(存储分区、存储挂载、docker迁移)

前言&#xff1a;由于目前机器存储空间不够&#xff0c;所以‘斥巨资’加了一块2T的机械硬盘&#xff0c;下面是对linux扩容的一系列操作&#xff0c;包含了磁盘空间的创建、删除&#xff1b;存储挂载&#xff1b;docker迁移&#xff1b;anaconda3迁移等。 一、存储分区 1.1 …

layui合并table相同内的行

<table border"1" id"table1" class"layui-table"><thead><tr><th><b>姓名</b></th><th><b>项目</b></th><th><b>任务</b></th><th><b>…