ip 请求次数限制
This commit is contained in:
83
src/main/java/com/sqx/common/aspect/IpAccessCounter.java
Normal file
83
src/main/java/com/sqx/common/aspect/IpAccessCounter.java
Normal 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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user