通过Guava实现ip限流访问

一分钟内某个ip请求制定接口超过10次,则禁止该ip 10分钟内不能访问,通过Guava实现一个拦截器,拦截指定接口来处理

 

mport com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class IpAccessLimit {

    private final Cache<String, AtomicInteger> ipRequestCounts;
    private final Cache<String, Boolean> bannedIps;

    public IpAccessLimit() {
        // 设置缓存过期时间为1分钟
        this.ipRequestCounts = CacheBuilder.newBuilder()
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .build();

        // 设置禁止访问的缓存过期时间为10分钟
        this.bannedIps = CacheBuilder.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build();
    }

    /**
     * 检查IP是否可以访问
     *
     * @param ip IP地址
     * @return 如果可以访问返回true,否则返回false
     */
//    public boolean canAccess2(String ip) {
//        RateLimiter rateLimiter = ipRateLimiters.getIfPresent(ip);
//        if (rateLimiter == null) {
//            // 初始化新的限流器,每秒最多允许10次请求
//            rateLimiter = RateLimiter.create(10.0/60.0);
//            ipRateLimiters.put(ip, rateLimiter);
//        }
//        return rateLimiter.tryAcquire();
//    }


    /**
     * 检查IP是否可以访问
     *
     * @param ip IP地址
     * @return 如果可以访问返回true,否则返回false
     */
    public boolean canAccess(String ip) {
        // 检查是否在禁止访问列表中
        if (bannedIps.getIfPresent(ip) != null) {
            return false;
        }

        AtomicInteger requestCount = ipRequestCounts.getIfPresent(ip);
        if (requestCount == null) {
            requestCount = new AtomicInteger(0);
            ipRequestCounts.put(ip, requestCount);
        }

        int count = requestCount.incrementAndGet();

        // 如果当前分钟内的请求次数超过10次
        if (count > 10) {
            // 将该IP加入到禁止访问列表中
            bannedIps.put(ip, true);
            return false;
        }

        return true;
    }
}

 

mport javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import java.util.regex.Pattern;

public class IpAccessFilter implements Filter {

    private static final IpAccessLimit ipAccessLimit = new IpAccessLimit();

    protected final Logger log = LoggerFactory.getLogger(IpAccessFilter.class);

    private Pattern limitedUrlPattern;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化需要限制的URL模式
        limitedUrlPattern = Pattern.compile(".*LoginAction\\.action$");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        // 将 ServletResponse 转换为 HttpServletResponse
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        String IPAddr = Browser.getIpAddr(request);
        String requestURI = request.getRequestURI();

        // 只对特定的URL进行访问次数限制
        if (limitedUrlPattern.matcher(requestURI).matches()) {
            if (ipAccessLimit.canAccess(IPAddr)) {
                filterChain.doFilter(servletRequest, servletResponse);
            } else {
                log.error("Too many requests from this IP address: {}",IPAddr);
                // 处理超出访问次数的情况,例如返回429 Too Many Requests状态码
                httpResponse.setStatus(429);
                httpResponse.getWriter().write("Too many requests, please try again later!");
            }
        } else {
            // 对其他URL不做限制,直接放行
            filterChain.doFilter(request, servletResponse);
        }
    }

    @Override
    public void destroy() {

    }
}

 

posted @ 2024-11-08 16:16  一去二三浪里小白龙  阅读(21)  评论(0编辑  收藏  举报
//增加一段JS脚本,为目录生成使用