ip 请求次数限制3

This commit is contained in:
GYJ 2025-03-23 20:53:49 +08:00
parent f9d44fb4a4
commit 172c4aeaaf
1 changed files with 59 additions and 35 deletions

View File

@ -1,83 +1,107 @@
package com.sqx.common.aspect;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
/**
* @author GYJoker
*/
@Slf4j
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, List<Long>> IP_ACCESS_TIMES = 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);
log.info("IpAccessCounter 开始清理超过一分钟的访问记录,清理前 IP_ACCESS_TIMES 大小: {}", IP_ACCESS_TIMES.size());
// 用于记录移除的 IP 集合
Set<String> removedIps = new HashSet<>();
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 是否可以访问
public static boolean canAccess(String ip, Integer maxAccessCount) {
if (isBlacklisted(ip)) {
log.info("IP {} 被阻止访问,因为在黑名单中", 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);
}
List<Long> accessTimes = IP_ACCESS_TIMES.computeIfAbsent(ip, k -> new ArrayList<>());
// 移除超过一分钟的访问时间记录
accessTimes.removeIf(time -> currentTime - time > ONE_MINUTE);
if (accessTimes.size() + 1 > maxAccessCount) {
addToBlacklist(ip);
log.info("IP {} 因一分钟内访问次数超过 {} 次,被加入黑名单", ip, maxAccessCount);
return false;
}
accessTimes.add(currentTime);
log.info("IP {} 在一分钟内第 {} 次访问", ip, accessTimes.size());
return true;
}
// 检查 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 加入黑名单
private static void addToBlacklist(String ip) {
BLACKLIST.put(ip, System.currentTimeMillis());
IP_ACCESS_COUNT.remove(ip);
IP_FIRST_ACCESS_TIME.remove(ip);
IP_ACCESS_TIMES.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";
for (int i = 0; i < 150; i++) {
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"));
}
}
}