自学内容网 自学内容网

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());
}


原文地址:https://blog.csdn.net/a983677218/article/details/142996790

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!