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

Springboot中基于 IP 地址的请求速率限制拦截器

       基于 IP 地址的请求速率限制拦截器,使用了 Bucket4j 库来管理请求的令牌桶。下面是对代码的详细解释,以及如何在触发请求拒绝时将 IP 地址加入黑名单的实现。  

      导入依赖

        <dependency>
            <groupId>com.github.vladimir-bukhtoyarov</groupId>
            <artifactId>bucket4j-core</artifactId>
            <version>6.0.2</version>
        </dependency>

      RateLimitInterceptor拦截器类

import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Bucket4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class RateLimitInterceptor implements HandlerInterceptor {

    private final Bandwidth limit = Bandwidth.simple(100, Duration.ofMinutes(1));
    private final ConcurrentHashMap<String, Bucket> buckets = new ConcurrentHashMap<>();
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate; // Redis 模板

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String ip = request.getRemoteAddr();
        log.info("当前访问ip: {}", ip);

        // 检查 IP 是否在黑名单中
        if (isBlacklisted(ip)) {
            response.setStatus(403); // 返回 403 状态码,表示禁止访问
            return false; // 拒绝请求
        }

        Bucket bucket = buckets.computeIfAbsent(ip, key -> Bucket4j.builder().addLimit(limit).build());

        if (bucket.tryConsume(1)) {
            return true; // 允许请求
        } else {
            // 将 IP 加入黑名单
            blacklistIp(ip);
            response.setStatus(429); // 返回 429 状态码
            return false; // 拒绝请求
        }
    }

    private boolean isBlacklisted(String ip) {
        // 检查 Redis 中是否存在该 IP
        return redisTemplate.hasKey("blacklist:" + ip);
    }

    private void blacklistIp(String ip) {
        // 将 IP 加入黑名单,设置过期时间为 1 小时
        redisTemplate.opsForValue().set("blacklist:" + ip, "true", Duration.ofHours(1));
    }
}

导入依赖:
Bucket4j:用于实现令牌桶算法的库。
HandlerInterceptor:Spring MVC 的拦截器接口,用于在请求处理之前和之后执行一些操作。
ConcurrentHashMap:用于存储每个 IP 地址对应的令牌桶,支持并发访问。
类定义:
RateLimitInterceptor 类实现了 HandlerInterceptor 接口。
带宽定义:
limit:定义了一个带宽限制,设置为每分钟允许 100 次请求。
桶存储:
buckets:使用 ConcurrentHashMap 存储每个 IP 地址对应的令牌桶。
请求处理:
preHandle 方法在请求处理之前被调用。
获取请求的 IP 地址。
使用 computeIfAbsent 方法获取或创建对应 IP 的桶。
尝试消耗一个令牌,如果成功,则允许请求继续;如果失败,则返回 429 状态码,表示请求过多。

RedisTemplate:

使用 RedisTemplate 来与 Redis 进行交互,检查和存储黑名单。
黑名单检查:

在 preHandle 方法中,首先检查请求的 IP 是否在黑名单中。如果在黑名单中,返回 403 状态码,拒绝请求。
黑名单添加:

如果请求被拒绝(即超过速率限制),调用 blacklistIp 方法将该 IP 加入黑名单,并设置过期时间为 1 小时。
黑名单检查方法:

isBlacklisted 方法用于检查 IP 是否在黑名单中。
通过这些修改,您可以有效地管理请求速率,并在触发拒绝请求时将 IP 地址加入黑名单,从而防止恶意请求。

web配置文件中注册拦截器

	/**
	 * 注册拦截器
	 * @Param [registry]
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 注册jwt拦截器
		registry.addInterceptor(new JWTInterceptor()).
				excludePathPatterns("/user/register", "/user/login", "/user/info", "/user/logout", ).//请求放行
				addPathPatterns("/**");
		// 注册速率限制拦截器
		registry.addInterceptor(new RateLimitInterceptor());
	}


http://www.kler.cn/a/354241.html

相关文章:

  • 安装fast_bev环境
  • 【ue5学习笔记2】在场景放入一个物体的蓝图输入事件无效?
  • 【快速上手】linux环境下Neo4j的安装与使用
  • 【MySQL】数据库 Navicat 可视化工具与 MySQL 命令行基本操作
  • 代码随想录D24-25 回溯算法03-04 Python
  • nodejs利用子进程child_process执行命令及child.stdout输出数据
  • Java 创建图形用户界面(GUI)组件详解之JFrame、JTextField、JTextArea、JPasswordField、JScrollPane、JLabel
  • docker安装kafka并使用SASL 进行身份验证
  • 无人机组装、维护、飞行技术全能培训详解
  • WebGl 使用缓冲区对象绘制多个点
  • 建造者模式(C++)
  • MySQL日期类型选择建议
  • FPGA学习-将modelsim中的波形数据保存到TXT文件方便MATLAB画图分析
  • 023 elasticsearch查询数据 高亮 分页 中文分词器 field的数据类型
  • 【布隆过滤器】
  • 在生产制造领域,可视化大屏的作用可以说无可替代。
  • 用Java爬虫API,轻松获取taobao商品SKU信息
  • C++_Stack和Queue的使用及其模拟实现
  • vue-vben-admin 首页加载慢优化 升级vite2到vite3
  • Qt-系统处理鼠标相关事件(57)
  • 阿里巴巴系列数据库
  • Halcon 使用二维像素分类对图像进行分割
  • Linux期末考试简答题题库
  • Ajax:原生ajax、使用FormData的细节问题,数据的载体
  • C#Process进程的使用,以及对ProcessInfo中所有的参数详细记录
  • java中,深克隆和浅克隆怎么用,有什么应用场景?-----面试题分享