ip 请求次数限制

This commit is contained in:
GYJ
2025-03-23 19:57:44 +08:00
parent bb593f2ad2
commit ac959c5015
2 changed files with 95 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
package com.sqx.common.aspect;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author GYJoker
*/
public class IpAccessCounter {
// 记录 IP 及其访问次数
private static final Map<String, Integer> IP_ACCESS_COUNT = new HashMap<>();
// 记录 IP 及其首次访问时间
private static final Map<String, Long> IP_FIRST_ACCESS_TIME = new HashMap<>();
// 黑名单,记录 IP 及其加入黑名单的时间
private static final Map<String, Long> BLACKLIST = new HashMap<>();
// 一分钟的毫秒数
private static final long ONE_MINUTE = 60 * 1000;
// 十分钟的毫秒数
private static final long TEN_MINUTES = 10 * ONE_MINUTE;
// 一分钟内允许的最大访问次数
static {
// 定时任务,每分钟清理一次访问计数
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
long currentTime = System.currentTimeMillis();
// 清理超过一分钟的访问记录
IP_FIRST_ACCESS_TIME.entrySet().removeIf(entry -> currentTime - entry.getValue() > ONE_MINUTE);
IP_ACCESS_COUNT.keySet().retainAll(IP_FIRST_ACCESS_TIME.keySet());
// 清理超过十分钟的黑名单记录
BLACKLIST.entrySet().removeIf(entry -> currentTime - entry.getValue() > TEN_MINUTES);
}
}, ONE_MINUTE, ONE_MINUTE);
}
// 检查 IP 是否可以访问
public static boolean canAccess(String ip, Integer maxAccessCount) {
if (isBlacklisted(ip)) {
return false;
}
long currentTime = System.currentTimeMillis();
if (!IP_FIRST_ACCESS_TIME.containsKey(ip)) {
IP_FIRST_ACCESS_TIME.put(ip, currentTime);
IP_ACCESS_COUNT.put(ip, 1);
} else {
if (currentTime - IP_FIRST_ACCESS_TIME.get(ip) <= ONE_MINUTE) {
int count = IP_ACCESS_COUNT.get(ip);
if (count + 1 > maxAccessCount) {
addToBlacklist(ip);
return false;
}
IP_ACCESS_COUNT.put(ip, count + 1);
} else {
IP_FIRST_ACCESS_TIME.put(ip, currentTime);
IP_ACCESS_COUNT.put(ip, 1);
}
}
return true;
}
// 检查 IP 是否在黑名单中
private static boolean isBlacklisted(String ip) {
return BLACKLIST.containsKey(ip) && System.currentTimeMillis() - BLACKLIST.get(ip) <= TEN_MINUTES;
}
// 将 IP 加入黑名单
private static void addToBlacklist(String ip) {
BLACKLIST.put(ip, System.currentTimeMillis());
IP_ACCESS_COUNT.remove(ip);
IP_FIRST_ACCESS_TIME.remove(ip);
}
public static void main(String[] args) {
String testIp = "192.168.1.1";
for (int i = 0; i < 150; i++) {
System.out.println("Attempt " + (i + 1) + ": " + (canAccess(testIp, 120) ? "Allowed" : "Blocked"));
}
}
}

View File

@@ -6,6 +6,7 @@ import com.sqx.common.exception.CzgException;
import com.sqx.common.exception.LimitException;
import com.sqx.common.utils.IPUtils;
import com.sqx.common.utils.Result;
import com.sqx.modules.common.service.CommonInfoService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
@@ -13,6 +14,7 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@@ -28,6 +30,10 @@ import java.util.concurrent.ConcurrentHashMap;
@Component
@Slf4j
public class RateLimitAspect {
@Autowired
private CommonInfoService commonInfoService;
private ConcurrentHashMap<String, RateLimiter> RATE_LIMITER = new ConcurrentHashMap<>();
private RateLimiter rateLimiter;
@@ -43,6 +49,12 @@ public class RateLimitAspect {
// 获取请求的 IP 地址
String ip = IPUtils.getIpAddr(request);
Integer maxAccessCount = Integer.parseInt(commonInfoService.findOne(935).getValue());
if (!IpAccessCounter.canAccess(ip, maxAccessCount)) {
log.info("一分钟内请求超过限制IP: {}, 最大访问次数: {}", ip, maxAccessCount);
throw new LimitException("访问频率过高,请稍后再试");
}
// 获取方法上的 @AccessLimit 注解
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();