ip 请求次数限制3

This commit is contained in:
GYJ
2025-03-23 20:53:49 +08:00
parent f9d44fb4a4
commit 172c4aeaaf

View File

@@ -1,83 +1,107 @@
package com.sqx.common.aspect; package com.sqx.common.aspect;
import java.util.HashMap; import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.Timer; import java.util.*;
import java.util.TimerTask;
/** /**
* @author GYJoker * @author GYJoker
*/ */
@Slf4j
public class IpAccessCounter { public class IpAccessCounter {
// 记录 IP 及其访问次数 // 记录 IP 及其每次访问的时间列表
private static final Map<String, Integer> IP_ACCESS_COUNT = new HashMap<>(); private static final Map<String, List<Long>> IP_ACCESS_TIMES = new HashMap<>();
// 记录 IP 及其首次访问时间
private static final Map<String, Long> IP_FIRST_ACCESS_TIME = new HashMap<>();
// 黑名单,记录 IP 及其加入黑名单的时间 // 黑名单,记录 IP 及其加入黑名单的时间
private static final Map<String, Long> BLACKLIST = new HashMap<>(); private static final Map<String, Long> BLACKLIST = new HashMap<>();
// 一分钟的毫秒数 // 一分钟的毫秒数
private static final long ONE_MINUTE = 60 * 1000; private static final long ONE_MINUTE = 60 * 1000;
// 十分钟的毫秒数 // 十分钟的毫秒数
private static final long TEN_MINUTES = 10 * ONE_MINUTE; private static final long TEN_MINUTES = 10 * ONE_MINUTE;
// 一分钟内允许的最大访问次数
static { static {
// 定时任务,每分钟清理一次访问计数 // 定时任务,每分钟清理一次访问记录
Timer timer = new Timer(); Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() {
@Override @Override
public void run() { public void run() {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
// 清理超过一分钟的访问记录 log.info("IpAccessCounter 开始清理超过一分钟的访问记录,清理前 IP_ACCESS_TIMES 大小: {}", IP_ACCESS_TIMES.size());
IP_FIRST_ACCESS_TIME.entrySet().removeIf(entry -> currentTime - entry.getValue() > ONE_MINUTE);
IP_ACCESS_COUNT.keySet().retainAll(IP_FIRST_ACCESS_TIME.keySet()); // 用于记录移除的 IP 集合
// 清理超过十分钟的黑名单记录 Set<String> removedIps = new HashSet<>();
BLACKLIST.entrySet().removeIf(entry -> currentTime - entry.getValue() > TEN_MINUTES); for (Map.Entry<String, List<Long>> entry : IP_ACCESS_TIMES.entrySet()) {
String ip = entry.getKey();
List<Long> accessTimes = entry.getValue();
accessTimes.removeIf(time -> currentTime - time > ONE_MINUTE);
if (accessTimes.isEmpty()) {
removedIps.add(ip);
}
}
removedIps.forEach(IP_ACCESS_TIMES::remove);
log.info("IpAccessCounter 清理完成,移除了 {} 个 IP 的访问记录,当前 IP_ACCESS_TIMES 大小: {}", removedIps.size(), IP_ACCESS_TIMES.size());
log.info("IpAccessCounter 开始清理超过十分钟的黑名单记录,清理前 BLACKLIST 大小: {}", BLACKLIST.size());
Set<String> removedBlacklistIps = new HashSet<>();
for (Map.Entry<String, Long> entry : BLACKLIST.entrySet()) {
String ip = entry.getKey();
long addedTime = entry.getValue();
if (currentTime - addedTime > TEN_MINUTES) {
removedBlacklistIps.add(ip);
}
}
removedBlacklistIps.forEach(BLACKLIST::remove);
log.info("IpAccessCounter 清理完成,移除了 {} 个 IP 的黑名单记录,当前 BLACKLIST 大小: {}", removedBlacklistIps.size(), BLACKLIST.size());
log.info("IpAccessCounter 定时清理访问记录和黑名单完成");
} }
}, ONE_MINUTE, ONE_MINUTE); }, ONE_MINUTE, 20000);
} }
// 检查 IP 是否可以访问 // 检查 IP 是否可以访问
public static boolean canAccess(String ip, Integer maxAccessCount) { public static boolean canAccess(String ip, Integer maxAccessCount) {
if (isBlacklisted(ip)) { if (isBlacklisted(ip)) {
log.info("IP {} 被阻止访问,因为在黑名单中", ip);
return false; return false;
} }
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (!IP_FIRST_ACCESS_TIME.containsKey(ip)) { List<Long> accessTimes = IP_ACCESS_TIMES.computeIfAbsent(ip, k -> new ArrayList<>());
IP_FIRST_ACCESS_TIME.put(ip, currentTime); // 移除超过一分钟的访问时间记录
IP_ACCESS_COUNT.put(ip, 1); accessTimes.removeIf(time -> currentTime - time > ONE_MINUTE);
} else { if (accessTimes.size() + 1 > maxAccessCount) {
if (currentTime - IP_FIRST_ACCESS_TIME.get(ip) <= ONE_MINUTE) { addToBlacklist(ip);
int count = IP_ACCESS_COUNT.get(ip); log.info("IP {} 因一分钟内访问次数超过 {} 次,被加入黑名单", ip, maxAccessCount);
if (count + 1 > maxAccessCount) { return false;
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);
}
} }
accessTimes.add(currentTime);
log.info("IP {} 在一分钟内第 {} 次访问", ip, accessTimes.size());
return true; return true;
} }
// 检查 IP 是否在黑名单中 // 检查 IP 是否在黑名单中
private static boolean isBlacklisted(String ip) { private static boolean isBlacklisted(String ip) {
return BLACKLIST.containsKey(ip) && System.currentTimeMillis() - BLACKLIST.get(ip) <= TEN_MINUTES; boolean result = BLACKLIST.containsKey(ip) && System.currentTimeMillis() - BLACKLIST.get(ip) <= TEN_MINUTES;
if (result) {
log.debug("IP {} 在黑名单中", ip);
}
return result;
} }
// 将 IP 加入黑名单 // 将 IP 加入黑名单
private static void addToBlacklist(String ip) { private static void addToBlacklist(String ip) {
BLACKLIST.put(ip, System.currentTimeMillis()); BLACKLIST.put(ip, System.currentTimeMillis());
IP_ACCESS_COUNT.remove(ip); IP_ACCESS_TIMES.remove(ip);
IP_FIRST_ACCESS_TIME.remove(ip); log.info("IP {} 已加入黑名单", ip);
} }
public static void main(String[] args) { public static void main(String[] args) throws InterruptedException {
String testIp = "192.168.1.1"; String testIp = "192.168.1.1";
for (int i = 0; i < 150; i++) { for (int i = 0; i < 150; i++) {
System.out.println("Attempt " + (i + 1) + ": " + (canAccess(testIp, 120) ? "Allowed" : "Blocked")); System.out.println("Attempt " + (i + 1) + ": " + (canAccess(testIp, 120) ? "Allowed" : "Blocked"));
} }
Thread.sleep(60 * 1000);
for (int i = 0; i < 150; i++) {
System.out.println("Attempt " + (i + 1) + ": " + (canAccess(testIp, 120) ? "Allowed" : "Blocked"));
}
} }
} }