1. 背景与痛点
在做后端开发时,我们常常会遇到这样的困境:
接口被恶意刷流量:比如某个查询接口被短时间大量调用,数据库连接数打满,最终拖垮整个服务。
缺少细粒度防护能力:很多系统只有粗糙的全局限流,但某些高价值 API(比如下单、支付、导出)并没有单独保护,一旦被攻击,影响范围很大。
风控策略难以落地:规则写死在代码里,每次调整都要改代码、打包、上线,运维成本高。
黑白名单管理混乱:一些临时封禁规则放在 Nginx,一些写在数据库,开发、运维、测试之间没有统一入口。
很多企业会引入 API 网关(如 Kong、Spring Cloud Gateway、Nginx+Lua)来解决,但这类方案往往过于"重量级":
需要额外维护一层组件,增加了部署复杂度。 学习和使用成本高,不适合中小团队快速落地。 对于单机部署或内网小系统来说,显得"杀鸡用牛刀"。
因此,一个非常现实的需求出现了:
在 Spring Boot 应用中内嵌一个轻量级 API 防火墙,做到单机级别的限流 + 风控 + 在线配置,无需依赖网关,也能快速解决安全与稳定性问题。



2. 设计思路
目标:在 SpringBoot 内嵌一层防护层,对所有 API 请求进行"前置检查"。
核心能力拆解:
黑白名单:支持配置IP白名单、黑名单;白名单优先级更高。
限流策略:
diff
- QPS 限流(如单接口每秒不超过 100 次请求)。
- 时间窗限流(如同一用户 1 分钟不超过 60 次调用)。
- 突发流量控制(避免短时间内瞬时压垮系统)。
风控规则:支持基于时间窗口的访问频率控制,如"单个IP在60秒内最多访问10次"。
在线配置:提供前端控制台,实时修改规则,立即生效,无需重启。
低侵入性 :以 Interceptor
或 Filter
形式接入,不影响现有业务逻辑。
架构示意:
markdown
┌────────────────────┐
│ API Firewall │ ← 拦截层(黑白名单 / 限流 / 风控)
└────────────────────┘
↓
┌────────────────────┐
│ 应用业务 API │
└────────────────────┘
3. 技术选型
Spring Boot Interceptor:最适合做请求前置校验,侵入性低。
Guava Cache:实现高性能内存缓存,支持过期策略和并发访问,也可使用Caffeine。
AtomicInteger + 时间窗口:基于计数器的限流实现,简单高效。
Spring Boot Actuator:提供健康检查和监控端点。
前端页面:Tailwind CSS + Chart.js:现代化响应式管理界面。
对于分布式场景,后续可以扩展 Redis + Lua 实现统一限流;但在本文场景下,先聚焦 单机轻量化防护。
4. 核心实现
4.1 定义规则实体
java
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class FirewallRule {
/**
* 主键ID
*/
private Long id;
/**
* 规则名称
*/
private String ruleName;
/**
* API路径匹配模式
*/
private String apiPattern;
/**
* QPS限制(每秒最大请求数)
*/
private Integer qpsLimit;
/**
* 单用户时间窗限制(分钟内最大请求数)
*/
private Integer userLimit;
/**
* 时间窗口(秒)
*/
private Integer timeWindow;
/**
* 是否启用
*/
private Boolean enabled;
/**
* 规则描述
*/
private String description;
/**
* 创建时间
*/
private LocalDateTime createdTime;
/**
* 更新时间
*/
private LocalDateTime updatedTime;
/**
* 检查API路径是否匹配此规则
*
* @param apiPath API路径
* @return 是否匹配
*/
public boolean matches(String apiPath) {
if (apiPattern == null || apiPath == null) {
return false;
}
// 支持通配符匹配
String pattern = apiPattern.replace("**", ".*").replace("*", "[^/]*");
return apiPath.matches(pattern);
}
}
4.2 规则管理器
java
@Slf4j
@Service
public class RuleManager {
@Autowired
private FirewallRuleMapper ruleMapper;
@Autowired
private FirewallBlacklistMapper blacklistMapper;
@Autowired
private FirewallWhitelistMapper whitelistMapper;
/**
* 规则缓存
*/
private final Map<String, FirewallRule> ruleCache = new ConcurrentHashMap<>();
/**
* 黑名单缓存
*/
private final Map<String, FirewallBlacklist> blacklistCache = new ConcurrentHashMap<>();
/**
* 白名单缓存
*/
private final Map<String, FirewallWhitelist> whitelistCache = new ConcurrentHashMap<>();
/**
* 初始化加载规则
*/
@PostConstruct
public void init() {
log.info("初始化防火墙规则管理器...");
refreshRules();
refreshBlacklist();
refreshWhitelist();
log.info("防火墙规则管理器初始化完成,加载规则: {}, 黑名单: {}, 白名单: {}",
ruleCache.size(), blacklistCache.size(), whitelistCache.size());
}
/**
* 获取匹配指定API路径的规则
*
* @param apiPath API路径
* @return 匹配的规则,如果没有匹配则返回null
*/
public FirewallRule getMatchingRule(String apiPath) {
if (apiPath == null) {
return null;
}
// 优先精确匹配
FirewallRule exactMatch = ruleCache.get(apiPath);
if (exactMatch != null && exactMatch.isEffectiveEnabled()) {
return exactMatch;
}
// 模式匹配
for (FirewallRule rule : ruleCache.values()) {
if (rule.isEffectiveEnabled() && rule.matches(apiPath)) {
return rule;
}
}
return null;
}
/**
* 检查IP是否在黑名单中
*
* @param ipAddress IP地址
* @return 是否在黑名单中
*/
public boolean isBlacklisted(String ipAddress) {
if (ipAddress == null) {
return false;
}
for (FirewallBlacklist blacklist : blacklistCache.values()) {
if (blacklist.isValid() && blacklist.matches(ipAddress)) {
return true;
}
}
return false;
}
/**
* 检查IP是否在白名单中
*
* @param ipAddress IP地址
* @return 是否在白名单中
*/
public boolean isWhitelisted(String ipAddress) {
if (ipAddress == null) {
return false;
}
for (FirewallWhitelist whitelist : whitelistCache.values()) {
if (whitelist.isValid() && whitelist.matches(ipAddress)) {
return true;
}
}
return false;
}
/**
* 定时刷新缓存
*/
@Scheduled(fixedRate = 300000) // 每5分钟刷新一次
public void scheduledRefresh() {
try {
refreshRules();
refreshBlacklist();
refreshWhitelist();
log.debug("定时刷新防火墙规则缓存完成");
} catch (Exception e) {
log.error("定时刷新防火墙规则缓存失败", e);
}
}
}
4.3 拦截器实现逻辑
java
@Slf4j
@Component
public class FirewallInterceptor implements HandlerInterceptor {
@Autowired
private RuleManager ruleManager;
@Autowired
private FirewallService firewallService;
@Value("${firewall.default.qps-limit:100}")
private int defaultQpsLimit;
@Value("${firewall.default.user-limit:1000}")
private int defaultUserLimit;
@Value("${firewall.default.time-window:60}")
private int defaultTimeWindow;
/**
* QPS限制缓存 - 存储每个IP+API的访问计数
*/
private final Cache<String, AtomicInteger> qpsCache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(1, TimeUnit.MINUTES)
.build();
/**
* 用户限制缓存 - 存储每个IP的访问计数
*/
private final Cache<String, AtomicInteger> userCache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(1, TimeUnit.HOURS)
.build();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
String ipAddress = getClientIpAddress(request);
String apiPath = request.getRequestURI();
String userAgent = request.getHeader("User-Agent");
String method = request.getMethod();
log.debug("防火墙拦截检查: IP={}, API={}, Method={}", ipAddress, apiPath, method);
try {
// 1. 检查白名单
if (ruleManager.isWhitelisted(ipAddress)) {
log.debug("IP {} 在白名单中,允许访问", ipAddress);
logAccess(ipAddress, apiPath, userAgent, method, 200, null, startTime);
return true;
}
// 2. 检查黑名单
if (ruleManager.isBlacklisted(ipAddress)) {
log.warn("IP {} 在黑名单中,拒绝访问", ipAddress);
blockRequest(response, "IP地址被列入黑名单", 403);
logAccess(ipAddress, apiPath, userAgent, method, 403, "IP黑名单拦截", startTime);
return false;
}
// 3. 获取匹配的防火墙规则
FirewallRule rule = ruleManager.getMatchingRule(apiPath);
if (rule == null) {
// 使用默认规则
rule = createDefaultRule(apiPath);
}
// 4. QPS限制检查
if (!checkQpsLimit(ipAddress, apiPath, rule)) {
log.warn("IP {} 访问 {} 超过QPS限制 {}", ipAddress, apiPath, rule.getEffectiveQpsLimit());
blockRequest(response, "访问频率过高,请稍后再试", 429);
logAccess(ipAddress, apiPath, userAgent, method, 429, "QPS限制拦截", startTime);
return false;
}
// 5. 用户限制检查
if (!checkUserLimit(ipAddress, rule)) {
log.warn("IP {} 超过用户限制 {}", ipAddress, rule.getEffectiveUserLimit());
blockRequest(response, "访问次数超过限制,请稍后再试", 429);
logAccess(ipAddress, apiPath, userAgent, method, 429, "用户限制拦截", startTime);
return false;
}
// 6. 记录正常访问
logAccess(ipAddress, apiPath, userAgent, method, 200, null, startTime);
log.debug("IP {} 访问 {} 通过防火墙检查", ipAddress, apiPath);
return true;
} catch (Exception e) {
log.error("防火墙拦截器处理异常: IP={}, API={}", ipAddress, apiPath, e);
logAccess(ipAddress, apiPath, userAgent, method, 500, "系统异常", startTime);
return true; // 异常情况下允许通过,避免影响正常业务
}
}
/**
* 检查QPS限制
*/
private boolean checkQpsLimit(String ipAddress, String apiPath, FirewallRule rule) {
String key = ipAddress + ":" + apiPath;
int qpsLimit = rule.getEffectiveQpsLimit();
if (qpsLimit <= 0) {
return true; // 无限制
}
AtomicInteger counter = qpsCache.getIfPresent(key);
if (counter == null) {
counter = new AtomicInteger(0);
qpsCache.put(key, counter);
}
int currentCount = counter.incrementAndGet();
return currentCount <= qpsLimit;
}
/**
* 检查用户限制
*/
private boolean checkUserLimit(String ipAddress, FirewallRule rule) {
int userLimit = rule.getEffectiveUserLimit();
if (userLimit <= 0) {
return true; // 无限制
}
AtomicInteger counter = userCache.getIfPresent(ipAddress);
if (counter == null) {
counter = new AtomicInteger(0);
userCache.put(ipAddress, counter);
}
int currentCount = counter.incrementAndGet();
return currentCount <= userLimit;
}
/**
* 获取客户端真实IP地址
*/
private String getClientIpAddress(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
return xForwardedFor.split(",")[0].trim();
}
String xRealIp = request.getHeader("X-Real-IP");
if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
return xRealIp;
}
return request.getRemoteAddr();
}
}
4.4 在线配置接口
java
@Slf4j
@RestController
@RequestMapping("/api/firewall")
@CrossOrigin(origins = "*") // 允许跨域访问
public class FirewallController {
@Autowired
private RuleManager ruleManager;
@Autowired
private FirewallService firewallService;
@Autowired
private FirewallInterceptor firewallInterceptor;
/**
* 获取所有防火墙规则
*/
@GetMapping("/rules")
public ResponseEntity<List<FirewallRule>> getRules() {
try {
List<FirewallRule> rules = ruleManager.getAllRules();
return ResponseEntity.ok(rules);
} catch (Exception e) {
log.error("获取防火墙规则失败", e);
return ResponseEntity.status(500).build();
}
}
/**
* 创建或更新防火墙规则
*/
@PostMapping("/rules")
public ResponseEntity<Map<String, Object>> saveRule(@RequestBody FirewallRule rule) {
Map<String, Object> result = new HashMap<>();
try {
boolean success = ruleManager.saveRule(rule);
if (success) {
result.put("success", true);
result.put("message", "规则保存成功");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "规则保存失败");
return ResponseEntity.status(500).body(result);
}
} catch (Exception e) {
log.error("保存防火墙规则失败", e);
result.put("success", false);
result.put("message", "系统异常: " + e.getMessage());
return ResponseEntity.status(500).body(result);
}
}
/**
* 删除防火墙规则
*/
@DeleteMapping("/rules/{id}")
public ResponseEntity<Map<String, Object>> deleteRule(@PathVariable Long id) {
Map<String, Object> result = new HashMap<>();
try {
boolean success = ruleManager.deleteRule(id);
if (success) {
result.put("success", true);
result.put("message", "规则删除成功");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "规则删除失败");
return ResponseEntity.status(500).body(result);
}
} catch (Exception e) {
log.error("删除防火墙规则失败", e);
result.put("success", false);
result.put("message", "系统异常: " + e.getMessage());
return ResponseEntity.status(500).body(result);
}
}
/**
* 获取黑名单列表
*/
@GetMapping("/blacklist")
public ResponseEntity<List<FirewallBlacklist>> getBlacklist() {
try {
List<FirewallBlacklist> blacklist = ruleManager.getAllBlacklist();
return ResponseEntity.ok(blacklist);
} catch (Exception e) {
log.error("获取黑名单失败", e);
return ResponseEntity.status(500).build();
}
}
/**
* 添加黑名单
*/
@PostMapping("/blacklist")
public ResponseEntity<Map<String, Object>> addBlacklist(@RequestBody FirewallBlacklist blacklist) {
Map<String, Object> result = new HashMap<>();
try {
boolean success = ruleManager.addBlacklist(blacklist);
if (success) {
result.put("success", true);
result.put("message", "黑名单添加成功");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "黑名单添加失败");
return ResponseEntity.status(500).body(result);
}
} catch (Exception e) {
log.error("添加黑名单失败", e);
result.put("success", false);
result.put("message", "系统异常: " + e.getMessage());
return ResponseEntity.status(500).body(result);
}
}
/**
* 获取访问日志
*/
@GetMapping("/logs")
public ResponseEntity<List<FirewallAccessLog>> getLogs(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String ipAddress,
@RequestParam(required = false) String apiPath) {
try {
List<FirewallAccessLog> logs = firewallService.getAccessLogs(page, size, ipAddress, apiPath);
return ResponseEntity.ok(logs);
} catch (Exception e) {
log.error("获取访问日志失败", e);
return ResponseEntity.status(500).build();
}
}
/**
* 获取统计数据
*/
@GetMapping("/statistics")
public ResponseEntity<Map<String, Object>> getStatistics(
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
try {
Map<String, Object> statistics = firewallService.getStatistics(startDate, endDate);
return ResponseEntity.ok(statistics);
} catch (Exception e) {
log.error("获取统计数据失败", e);
return ResponseEntity.status(500).build();
}
}
}
这样,我们就有了一个"可实时更新"的防火墙层。
5. 前端控制台
一个现代化的管理页面,基于 HTML5 + Tailwind CSS + JavaScript
,提供完整的防火墙管理功能:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web防火墙控制台</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body class="bg-gray-50 font-sans">
<div class="min-h-screen">
<!-- 顶部导航栏 -->
<nav class="bg-white shadow-lg border-b border-gray-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<!-- 左侧 Logo 和导航 -->
<div class="flex items-center space-x-8">
<div class="flex items-center space-x-3">
<div class="bg-blue-600 p-2 rounded-lg">
<i class="fas fa-shield-alt text-white text-xl"></i>
</div>
<span class="text-xl font-bold text-gray-900">Web防火墙</span>
</div>
<!-- 主导航菜单 -->
<div class="hidden md:flex space-x-4">
<button class="nav-btn active" data-page="dashboard">
<i class="fas fa-tachometer-alt mr-2 text-blue-500"></i>仪表盘
</button>
<button class="nav-btn" data-page="rules">
<i class="fas fa-list-ul mr-2 text-green-500"></i>规则管理
</button>
<button class="nav-btn" data-page="blacklist">
<i class="fas fa-ban mr-2 text-red-500"></i>黑名单
</button>
<button class="nav-btn" data-page="whitelist">
<i class="fas fa-check-circle mr-2 text-emerald-500"></i>白名单
</button>
<button class="nav-btn" data-page="logs">
<i class="fas fa-file-alt mr-2 text-purple-500"></i>访问日志
</button>
</div>
</div>
</div>
</div>
</nav>
<!-- 主内容区 -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- 仪表盘页面 -->
<div id="dashboard-page" class="page-content">
<div class="mb-8">
<h1 class="text-3xl font-bold text-gray-900">仪表盘</h1>
<p class="text-gray-600 mt-2">实时监控系统状态和安全指标</p>
</div>
<!-- 统计卡片 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-2 bg-blue-100 rounded-lg">
<i class="fas fa-globe text-blue-600 text-xl"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-600">今日请求</p>
<p class="text-2xl font-bold text-gray-900" id="today-requests">0</p>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-2 bg-red-100 rounded-lg">
<i class="fas fa-shield-alt text-red-600 text-xl"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-600">今日拦截</p>
<p class="text-2xl font-bold text-gray-900" id="today-blocked">0</p>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-2 bg-green-100 rounded-lg">
<i class="fas fa-check-circle text-green-600 text-xl"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-600">活跃规则</p>
<p class="text-2xl font-bold text-gray-900" id="active-rules">0</p>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-2 bg-yellow-100 rounded-lg">
<i class="fas fa-ban text-yellow-600 text-xl"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-600">黑名单IP</p>
<p class="text-2xl font-bold text-gray-900" id="blacklist-count">0</p>
</div>
</div>
</div>
</div>
<!-- 图表区域 -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">请求趋势</h3>
<canvas id="requestChart" width="400" height="200"></canvas>
</div>
<div class="bg-white rounded-lg shadow p-6">
<h3 class="text-lg font-semibold text-gray-900 mb-4">拦截分布</h3>
<canvas id="blockChart" width="400" height="200"></canvas>
</div>
</div>
</div>
</main>
</div>
<!-- JavaScript 应用逻辑 -->
<script src="/js/app.js"></script>
</body>
</html>
核心 JavaScript 功能
javascript
class FirewallApp {
constructor() {
this.apiBase = '/api/firewall';
this.currentPage = 'dashboard';
this.rules = [];
this.charts = {};
this.init();
}
async init() {
this.bindEvents();
await this.loadDashboard();
this.startAutoRefresh();
}
// 加载仪表盘数据
async loadDashboard() {
try {
const [rules, blacklist, statistics] = await Promise.all([
this.fetchData('/rules'),
this.fetchData('/blacklist'),
this.fetchData('/statistics?startDate=' + this.getDateString(-7) + '&endDate=' + this.getDateString(0))
]);
this.updateDashboardStats(rules, blacklist, statistics);
this.updateCharts(statistics);
} catch (error) {
console.error('加载仪表盘数据失败:', error);
}
}
// 更新统计数据
updateDashboardStats(rules, blacklist, statistics) {
document.getElementById('today-requests').textContent = statistics.todayRequests || 0;
document.getElementById('today-blocked').textContent = statistics.todayBlocked || 0;
document.getElementById('active-rules').textContent = rules.filter(r => r.enabled).length;
document.getElementById('blacklist-count').textContent = blacklist.length;
}
// 更新图表
updateCharts(statistics) {
// 请求趋势图
if (this.charts.requestChart) {
this.charts.requestChart.destroy();
}
const ctx1 = document.getElementById('requestChart').getContext('2d');
this.charts.requestChart = new Chart(ctx1, {
type: 'line',
data: {
labels: statistics.dates || [],
datasets: [{
label: '总请求',
data: statistics.requests || [],
borderColor: 'rgb(59, 130, 246)',
backgroundColor: 'rgba(59, 130, 246, 0.1)',
tension: 0.4
}, {
label: '被拦截',
data: statistics.blocked || [],
borderColor: 'rgb(239, 68, 68)',
backgroundColor: 'rgba(239, 68, 68, 0.1)',
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
}
// 获取数据
async fetchData(endpoint) {
const response = await fetch(this.apiBase + endpoint);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
// 自动刷新
startAutoRefresh() {
setInterval(() => {
if (this.currentPage === 'dashboard') {
this.loadDashboard();
}
}, 30000); // 每30秒刷新一次
}
}
// 初始化应用
new FirewallApp();
实时仪表盘 :显示请求量、拦截数、活跃规则等关键指标 可视化图表 :请求趋势和拦截分布的图表展示 规则管理 :在线添加、修改、删除防火墙规则 黑白名单 :IP地址的黑白名单管理 访问日志:详细的访问记录和拦截日志
6. 配置文件
在 application.yml
中设置完整的防火墙参数:
yaml
server:
port: 8080
servlet:
context-path: /
spring:
application:
name: springboot-firewall
# Jackson配置
jackson:
serialization:
write-dates-as-timestamps: false
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
# 数据源配置 (H2内嵌数据库)
datasource:
url: jdbc:h2:mem:firewall;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: sa
password:
# H2控制台配置
h2:
console:
enabled: true
path: /h2-console
settings:
web-allow-others: true
# SQL初始化
sql:
init:
mode: always
schema-locations: classpath:schema.sql
data-locations: classpath:data.sql
# MyBatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.firewall.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 管理端点配置
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
# 日志配置
logging:
level:
com.example.firewall: DEBUG
org.springframework.web: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
# 防火墙配置
firewall:
enabled: true
default-qps-limit: 100
default-user-limit: 60
cache-size: 1000
exclude-paths:
- /firewall/**
- /h2-console/**
- /actuator/**
- /static/**
- /favicon.ico
7. 实战应用场景
7.1 中小型系统防护
电商网站场景:
yaml
# 针对订单接口的特殊规则
- ruleName: "订单保护"
apiPattern: "/api/orders/**"
qpsLimit: 50
userLimit: 5
timeWindow: 60
enabled: true
description: "防止恶意刷单和重复下单"
内容平台场景:
yaml
# 评论和点赞接口限制
- ruleName: "内容互动限制"
apiPattern: "/api/comments/**,/api/likes/**"
qpsLimit: 200
userLimit: 20
timeWindow: 300
enabled: true
description: "防止垃圾评论和刷赞行为"
7.2 突发流量应对
营销活动期间:
java
// 通过API动态调整规则
POST /api/firewall/rules
{
"ruleName": "秒杀活动保护",
"apiPattern": "/api/seckill/**",
"qpsLimit": 1000,
"userLimit": 1,
"timeWindow": 60,
"enabled": true,
"description": "秒杀活动期间特殊限制"
}
爬虫防护:
java
// 手动添加黑名单示例
FirewallBlacklist blacklist = new FirewallBlacklist();
blacklist.setIpAddress("192.168.1.100");
blacklist.setReason("恶意爬虫行为");
blacklist.setExpireTime(LocalDateTime.now().plusHours(24));
blacklist.setEnabled(true);
ruleManager.addBlacklist(blacklist);
log.info("IP {} 已手动加入黑名单", blacklist.getIpAddress());
7.3 部署和运维
Docker 部署:
dockerfile
FROM openjdk:11-jre-slim
VOLUME /tmp
COPY target/springboot-firewall-1.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
监控集成:
yaml
# Prometheus 监控指标
management:
metrics:
tags:
application: firewall
export:
prometheus:
enabled: true
总结
本文实现了一个基于 SpringBoot 的轻量级 API 防火墙,通过拦截器机制提供实时防护能力。
系统采用 Guava Cache 实现高性能内存缓存,支持 QPS 限制和用户访问频率控制。
提供了完整的黑白名单管理功能,配备现代化的 Web 管理界面,支持规则的在线配置和实时生效。整体架构简洁高效,适合中小型项目快速集成使用。