本文目录导读:

我来详细讲解Java实现IP封禁的几种常见方案和案例。
基于内存的简易IP封禁
基础实现示例
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class SimpleIpBlocker {
// IP访问次数记录
private static ConcurrentHashMap<String, AtomicInteger> accessCount = new ConcurrentHashMap<>();
// 封禁的IP集合
private static ConcurrentHashMap<String, Long> blockedIps = new ConcurrentHashMap<>();
// 配置参数
private static final int MAX_ATTEMPTS = 10; // 最大尝试次数
private static final long BLOCK_DURATION = 60000; // 封禁时长(毫秒)
/**
* 检查IP是否被封禁
*/
public static boolean isBlocked(String ip) {
// 检查是否在封禁列表中
Long blockTime = blockedIps.get(ip);
if (blockTime != null) {
// 检查封禁是否过期
if (System.currentTimeMillis() - blockTime > BLOCK_DURATION) {
// 封禁过期,解除封禁
blockedIps.remove(ip);
accessCount.remove(ip);
return false;
}
return true;
}
return false;
}
/**
* 记录IP访问
*/
public static void recordAccess(String ip) {
if (isBlocked(ip)) {
return;
}
// 原子递增访问计数
AtomicInteger counter = accessCount.computeIfAbsent(ip, k -> new AtomicInteger(0));
int count = counter.incrementAndGet();
// 超过阈值则封禁
if (count >= MAX_ATTEMPTS) {
blockedIps.put(ip, System.currentTimeMillis());
System.out.println("IP " + ip + " 已被封禁,访问次数: " + count);
}
}
/**
* 手动解封IP
*/
public static void unblockIp(String ip) {
blockedIps.remove(ip);
accessCount.remove(ip);
System.out.println("IP " + ip + " 已被解封");
}
}
过滤器实现
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class IpBlockFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化配置
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取客户端IP
String clientIp = getClientIp(httpRequest);
// 检查IP是否被封禁
if (SimpleIpBlocker.isBlocked(clientIp)) {
httpResponse.setStatus(403);
httpResponse.getWriter().write("您的IP已被封禁");
return;
}
// 记录访问
SimpleIpBlocker.recordAccess(clientIp);
// 继续执行后续操作
chain.doFilter(request, response);
}
/**
* 获取真实客户端IP
*/
private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
@Override
public void destroy() {
// 清理资源
}
}
基于Redis的分布式IP封禁
Redis实现方案
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
public class RedisIpBlocker {
private JedisPool jedisPool;
// 缓存配置
private static final String BLOCK_PREFIX = "ip:block:";
private static final String COUNT_PREFIX = "ip:count:";
private static final int MAX_ATTEMPTS = 10;
private static final int BLOCK_DURATION = 600; // 秒
private static final int COUNT_WINDOW = 60; // 统计窗口(秒)
public RedisIpBlocker(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
/**
* 检查IP是否被封禁
*/
public boolean isBlocked(String ip) {
try (Jedis jedis = jedisPool.getResource()) {
String blockKey = BLOCK_PREFIX + ip;
return jedis.exists(blockKey);
}
}
/**
* 记录访问并检查是否需要封禁
*/
public boolean checkAndRecord(String ip) {
try (Jedis jedis = jedisPool.getResource()) {
String countKey = COUNT_PREFIX + ip;
// 使用Lua脚本保证原子性
String luaScript =
"local count = redis.call('incr', KEYS[1])\n" +
"redis.call('expire', KEYS[1], ARGV[1])\n" +
"if count >= tonumber(ARGV[2]) then\n" +
" redis.call('setex', KEYS[2], ARGV[3], '1')\n" +
" return 1\n" +
"end\n" +
"return 0";
Object result = jedis.eval(luaScript, 2,
countKey,
BLOCK_PREFIX + ip,
String.valueOf(COUNT_WINDOW),
String.valueOf(MAX_ATTEMPTS),
String.valueOf(BLOCK_DURATION));
return "1".equals(result.toString());
}
}
/**
* 解封IP
*/
public void unblockIp(String ip) {
try (Jedis jedis = jedisPool.getResource()) {
Pipeline pipeline = jedis.pipelined();
pipeline.del(BLOCK_PREFIX + ip);
pipeline.del(COUNT_PREFIX + ip);
pipeline.sync();
}
}
/**
* 获取IP访问次数
*/
public long getAccessCount(String ip) {
try (Jedis jedis = jedisPool.getResource()) {
String count = jedis.get(COUNT_PREFIX + ip);
return count != null ? Long.parseLong(count) : 0;
}
}
/**
* 获取被封禁的IP列表
*/
public Set<String> getBlockedIps() {
try (Jedis jedis = jedisPool.getResource()) {
return jedis.keys(BLOCK_PREFIX + "*");
}
}
}
Spring Boot集成Redis配置
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
@Bean
public RedisScript<Long> ipBlockScript() {
String script =
"local count = redis.call('incr', KEYS[1])\n" +
"redis.call('expire', KEYS[1], ARGV[1])\n" +
"if count >= tonumber(ARGV[2]) then\n" +
" redis.call('setex', KEYS[2], ARGV[3], '1')\n" +
" return 1\n" +
"end\n" +
"return 0";
return new DefaultRedisScript<>(script, Long.class);
}
}
完整的Spring Boot应用示例
配置类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private IpBlockInterceptor ipBlockInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(ipBlockInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/health", "/api/unblock");
}
}
拦截器实现
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class IpBlockInterceptor implements HandlerInterceptor {
@Autowired
private RedisIpBlocker redisIpBlocker;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String clientIp = getClientIp(request);
// 检查是否被封禁
if (redisIpBlocker.isBlocked(clientIp)) {
response.setStatus(403);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":403,\"message\":\"IP已被封禁\"}");
return false;
}
// 记录访问并检查
if (redisIpBlocker.checkAndRecord(clientIp)) {
response.setStatus(403);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":403,\"message\":\"访问频繁,IP已被封禁\"}");
return false;
}
return true;
}
private String getClientIp(HttpServletRequest request) {
// 获取真实IP的代码同上
// ...
}
}
封禁管理接口
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/ip-block")
public class IpBlockController {
@Autowired
private RedisIpBlocker redisIpBlocker;
/**
* 手动封禁IP
*/
@PostMapping("/block")
public String blockIp(@RequestParam String ip,
@RequestParam(required = false, defaultValue = "3600") long duration) {
// 实现手动封禁
return "IP已封禁";
}
/**
* 解封IP
*/
@PostMapping("/unblock")
public String unblockIp(@RequestParam String ip) {
redisIpBlocker.unblockIp(ip);
return "IP已解封";
}
/**
* 查询IP状态
*/
@GetMapping("/status")
public Map<String, Object> getIpStatus(@RequestParam String ip) {
Map<String, Object> result = new HashMap<>();
result.put("ip", ip);
result.put("blocked", redisIpBlocker.isBlocked(ip));
result.put("accessCount", redisIpBlocker.getAccessCount(ip));
return result;
}
}
高级封禁策略
滑动窗口算法
public class SlidingWindowBlocker {
private static final int WINDOW_SIZE = 60; // 窗口大小(秒)
private static final int MAX_REQUESTS = 100; // 最大请求数
private final RedisTemplate<String, String> redisTemplate;
public boolean checkSlidingWindow(String ip) {
String key = "ip:sliding:" + ip;
long now = System.currentTimeMillis() / 1000;
DefaultRedisScript<Long> script = new DefaultRedisScript<>();
script.setScriptText(
"redis.call('zremrangebyscore', KEYS[1], 0, ARGV[1] - 3600)\n" +
"local count = redis.call('zcard', KEYS[1])\n" +
"if count < tonumber(ARGV[2]) then\n" +
" redis.call('zadd', KEYS[1], ARGV[1], ARGV[1])\n" +
" redis.call('expire', KEYS[1], ARGV[3])\n" +
" return 0\n" +
"end\n" +
"return 1"
);
script.setResultType(Long.class);
List<String> keys = Arrays.asList(key);
Long result = redisTemplate.execute(script, keys,
String.valueOf(now),
String.valueOf(MAX_REQUESTS),
String.valueOf(WINDOW_SIZE));
return result == 1;
}
}
动态阈值调整
public class DynamicThresholdBlocker {
// 动态调整访问阈值
public int getThreshold(String ip) {
// 根据IP的访问历史动态调整
String historyKey = "ip:history:" + ip;
// 获取过去24小时的访问次数
String count = redisTemplate.opsForValue().get(historyKey);
long totalCount = count != null ? Long.parseLong(count) : 0;
// 根据访问频率动态调整阈值
if (totalCount > 10000) {
return 5; // 高频IP,降低阈值
} else if (totalCount > 1000) {
return 10;
} else {
return 20; // 正常IP,使用默认阈值
}
}
}
使用建议
部署配置
# application.yml
ip-block:
enabled: true
max-attempts: 10
block-duration: 600
count-window: 60
whitelist:
- 127.0.0.1
- 192.168.1.0/24
最佳实践
- 多层防护:结合Nginx、防火墙等多层防护
- 分段处理:不同接口使用不同的封禁策略
- 日志记录:记录所有封禁事件以便审计
- 白名单机制:对内网IP、健康检查等放行
- 自动解封:设置合理的自动解封时间
这个完整的Java IP封禁方案可以根据实际需求选择合适的实现方式。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播