ip 请求次数限制3
This commit is contained in:
parent
f9d44fb4a4
commit
172c4aeaaf
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue