开封市网站建设_网站建设公司_建站流程_seo优化
2026/1/18 9:19:31 网站建设 项目流程

👉这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料:

  • 《项目实战(视频)》:从书中学,往事上“练”

  • 《互联网高频面试题》:面朝简历学习,春暖花开

  • 《架构 x 系统设计》:摧枯拉朽,掌控面试高频场景题

  • 《精进 Java 学习指南》:系统学习,互联网主流技术栈

  • 《必读 Java 源码专栏》:知其然,知其所以然

👉这是一个或许对你有用的开源项目

国产Star破10w的开源项目,前端包括管理后台、微信小程序,后端支持单体、微服务架构

RBAC权限、数据权限、SaaS多租户、商城、支付、工作流、大屏报表、ERP、CRMAI大模型、IoT物联网等功能:

  • 多模块:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • 微服务:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

【国内首批】支持 JDK17/21+SpringBoot3、JDK8/11+Spring Boot2双版本

来源:风象南

  • 1. 背景与痛点

  • 2. 设计思路

  • 3. 技术选型

  • 4. 核心实现

  • 5. 前端控制台

  • 6. 配置文件

  • 7. 实战应用场景

  • 总结


1. 背景与痛点

在做后端开发时,我们常常会遇到这样的困境:

接口被恶意刷流量:比如某个查询接口被短时间大量调用,数据库连接数打满,最终拖垮整个服务。

缺少细粒度防护能力:很多系统只有粗糙的全局限流,但某些高价值 API(比如下单、支付、导出)并没有单独保护,一旦被攻击,影响范围很大。

风控策略难以落地:规则写死在代码里,每次调整都要改代码、打包、上线,运维成本高。

黑白名单管理混乱:一些临时封禁规则放在 Nginx,一些写在数据库,开发、运维、测试之间没有统一入口。

很多企业会引入API 网关(如 Kong、Spring Cloud Gateway、Nginx+Lua)来解决,但这类方案往往过于“重量级”:

需要额外维护一层组件,增加了部署复杂度。 学习和使用成本高,不适合中小团队快速落地。 对于单机部署或内网小系统来说,显得“杀鸡用牛刀”。

因此,一个非常现实的需求出现了:在 Spring Boot 应用中内嵌一个轻量级 API 防火墙,做到单机级别的限流 + 风控 + 在线配置,无需依赖网关,也能快速解决安全与稳定性问题。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

2. 设计思路

目标:在SpringBoot 内嵌一层防护层,对所有 API 请求进行“前置检查”。

核心能力拆解:

黑白名单:支持配置IP白名单、黑名单;白名单优先级更高。

限流策略

- QPS 限流(如单接口每秒不超过 100 次请求)。 - 时间窗限流(如同一用户 1 分钟不超过 60 次调用)。 - 突发流量控制(避免短时间内瞬时压垮系统)。

风控规则:支持基于时间窗口的访问频率控制,如"单个IP在60秒内最多访问10次"。

在线配置:提供前端控制台,实时修改规则,立即生效,无需重启。

低侵入性:以InterceptorFilter形式接入,不影响现有业务逻辑。

架构示意:

┌────────────────────┐ │ API Firewall │ ← 拦截层(黑白名单 / 限流 / 风控) └────────────────────┘ ↓ ┌────────────────────┐ │ 应用业务 API │ └────────────────────┘

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

3. 技术选型

Spring Boot Interceptor:最适合做请求前置校验,侵入性低。

Guava Cache:实现高性能内存缓存,支持过期策略和并发访问,也可使用Caffeine。

AtomicInteger + 时间窗口:基于计数器的限流实现,简单高效。

Spring Boot Actuator:提供健康检查和监控端点。

前端页面:Tailwind CSS + Chart.js:现代化响应式管理界面。

对于分布式场景,后续可以扩展 Redis + Lua 实现统一限流;但在本文场景下,先聚焦单机轻量化防护

4. 核心实现

4.1 定义规则实体
@Data @NoArgsConstructor @AllArgsConstructor @Builder publicclassFirewallRule { /** * 主键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 是否匹配 */ publicbooleanmatches(String apiPath) { if (apiPattern == null || apiPath == null) { returnfalse; } // 支持通配符匹配 Stringpattern= apiPattern.replace("**", ".*").replace("*", "[^/]*"); return apiPath.matches(pattern); } }
4.2 规则管理器
@Slf4j @Service publicclassRuleManager { @Autowired private FirewallRuleMapper ruleMapper; @Autowired private FirewallBlacklistMapper blacklistMapper; @Autowired private FirewallWhitelistMapper whitelistMapper; /** * 规则缓存 */ privatefinal Map<String, FirewallRule> ruleCache = newConcurrentHashMap<>(); /** * 黑名单缓存 */ privatefinal Map<String, FirewallBlacklist> blacklistCache = newConcurrentHashMap<>(); /** * 白名单缓存 */ privatefinal Map<String, FirewallWhitelist> whitelistCache = newConcurrentHashMap<>(); /** * 初始化加载规则 */ @PostConstruct publicvoidinit() { 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) { returnnull; } // 优先精确匹配 FirewallRuleexactMatch= ruleCache.get(apiPath); if (exactMatch != null && exactMatch.isEffectiveEnabled()) { return exactMatch; } // 模式匹配 for (FirewallRule rule : ruleCache.values()) { if (rule.isEffectiveEnabled() && rule.matches(apiPath)) { return rule; } } returnnull; } /** * 检查IP是否在黑名单中 * * @param ipAddress IP地址 * @return 是否在黑名单中 */ publicbooleanisBlacklisted(String ipAddress) { if (ipAddress == null) { returnfalse; } for (FirewallBlacklist blacklist : blacklistCache.values()) { if (blacklist.isValid() && blacklist.matches(ipAddress)) { returntrue; } } returnfalse; } /** * 检查IP是否在白名单中 * * @param ipAddress IP地址 * @return 是否在白名单中 */ publicbooleanisWhitelisted(String ipAddress) { if (ipAddress == null) { returnfalse; } for (FirewallWhitelist whitelist : whitelistCache.values()) { if (whitelist.isValid() && whitelist.matches(ipAddress)) { returntrue; } } returnfalse; } /** * 定时刷新缓存 */ @Scheduled(fixedRate = 300000)// 每5分钟刷新一次 publicvoidscheduledRefresh() { try { refreshRules(); refreshBlacklist(); refreshWhitelist(); log.debug("定时刷新防火墙规则缓存完成"); } catch (Exception e) { log.error("定时刷新防火墙规则缓存失败", e); } } }
4.3 拦截器实现逻辑
@Slf4j @Component publicclassFirewallInterceptorimplementsHandlerInterceptor { @Autowired private RuleManager ruleManager; @Autowired private FirewallService firewallService; @Value("${firewall.default.qps-limit:100}") privateint defaultQpsLimit; @Value("${firewall.default.user-limit:1000}") privateint defaultUserLimit; @Value("${firewall.default.time-window:60}") privateint defaultTimeWindow; /** * QPS限制缓存 - 存储每个IP+API的访问计数 */ privatefinal Cache<String, AtomicInteger> qpsCache = CacheBuilder.newBuilder() .maximumSize(10000) .expireAfterWrite(1, TimeUnit.MINUTES) .build(); /** * 用户限制缓存 - 存储每个IP的访问计数 */ privatefinal Cache<String, AtomicInteger> userCache = CacheBuilder.newBuilder() .maximumSize(10000) .expireAfterWrite(1, TimeUnit.HOURS) .build(); @Override publicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception { longstartTime= System.currentTimeMillis(); StringipAddress= getClientIpAddress(request); StringapiPath= request.getRequestURI(); StringuserAgent= request.getHeader("User-Agent"); Stringmethod= 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); returntrue; } // 2. 检查黑名单 if (ruleManager.isBlacklisted(ipAddress)) { log.warn("IP {} 在黑名单中,拒绝访问", ipAddress); blockRequest(response, "IP地址被列入黑名单", 403); logAccess(ipAddress, apiPath, userAgent, method, 403, "IP黑名单拦截", startTime); returnfalse; } // 3. 获取匹配的防火墙规则 FirewallRulerule= 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); returnfalse; } // 5. 用户限制检查 if (!checkUserLimit(ipAddress, rule)) { log.warn("IP {} 超过用户限制 {}", ipAddress, rule.getEffectiveUserLimit()); blockRequest(response, "访问次数超过限制,请稍后再试", 429); logAccess(ipAddress, apiPath, userAgent, method, 429, "用户限制拦截", startTime); returnfalse; } // 6. 记录正常访问 logAccess(ipAddress, apiPath, userAgent, method, 200, null, startTime); log.debug("IP {} 访问 {} 通过防火墙检查", ipAddress, apiPath); returntrue; } catch (Exception e) { log.error("防火墙拦截器处理异常: IP={}, API={}", ipAddress, apiPath, e); logAccess(ipAddress, apiPath, userAgent, method, 500, "系统异常", startTime); returntrue; // 异常情况下允许通过,避免影响正常业务 } } /** * 检查QPS限制 */ privatebooleancheckQpsLimit(String ipAddress, String apiPath, FirewallRule rule) { Stringkey= ipAddress + ":" + apiPath; intqpsLimit= rule.getEffectiveQpsLimit(); if (qpsLimit <= 0) { returntrue; // 无限制 } AtomicIntegercounter= qpsCache.getIfPresent(key); if (counter == null) { counter = newAtomicInteger(0); qpsCache.put(key, counter); } intcurrentCount= counter.incrementAndGet(); return currentCount <= qpsLimit; } /** * 检查用户限制 */ privatebooleancheckUserLimit(String ipAddress, FirewallRule rule) { intuserLimit= rule.getEffectiveUserLimit(); if (userLimit <= 0) { returntrue; // 无限制 } AtomicIntegercounter= userCache.getIfPresent(ipAddress); if (counter == null) { counter = newAtomicInteger(0); userCache.put(ipAddress, counter); } intcurrentCount= counter.incrementAndGet(); return currentCount <= userLimit; } /** * 获取客户端真实IP地址 */ private String getClientIpAddress(HttpServletRequest request) { StringxForwardedFor= request.getHeader("X-Forwarded-For"); if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) { return xForwardedFor.split(",")[0].trim(); } StringxRealIp= request.getHeader("X-Real-IP"); if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) { return xRealIp; } return request.getRemoteAddr(); } }
4.4 在线配置接口
@Slf4j @RestController @RequestMapping("/api/firewall") @CrossOrigin(origins = "*")// 允许跨域访问 publicclassFirewallController { @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 = newHashMap<>(); try { booleansuccess= 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 = newHashMap<>(); try { booleansuccess= 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 = newHashMap<>(); try { booleansuccess= 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,提供完整的防火墙管理功能:

<!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">class FirewallApp { constructor() { this.apiBase = '/api/firewall'; this.currentPage = 'dashboard'; this.rules = []; this.charts = {}; this.init(); } asyncinit() { this.bindEvents(); awaitthis.loadDashboard(); this.startAutoRefresh(); } // 加载仪表盘数据 asyncloadDashboard() { try { const [rules, blacklist, statistics] = awaitPromise.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 = newChart(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 } } } }); } // 获取数据 asyncfetchData(endpoint) { const response = awaitfetch(this.apiBase + endpoint); if (!response.ok) { thrownewError(`HTTP error! status: ${response.status}`); } returnawait response.json(); } // 自动刷新 startAutoRefresh() { setInterval(() => { if (this.currentPage === 'dashboard') { this.loadDashboard(); } }, 30000); // 每30秒刷新一次 } } // 初始化应用 newFirewallApp();

实时仪表盘:显示请求量、拦截数、活跃规则等关键指标可视化图表:请求趋势和拦截分布的图表展示规则管理:在线添加、修改、删除防火墙规则黑白名单:IP地址的黑白名单管理访问日志:详细的访问记录和拦截日志

6. 配置文件

application.yml中设置完整的防火墙参数:

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-ddHH: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 ># 针对订单接口的特殊规则 -ruleName:"订单保护" apiPattern:"/api/orders/**" qpsLimit:50 userLimit:5 timeWindow:60 enabled:true description: "防止恶意刷单和重复下单"

内容平台场景

# 评论和点赞接口限制 -ruleName:"内容互动限制" apiPattern:"/api/comments/**,/api/likes/**" qpsLimit:200 userLimit:20 timeWindow:300 enabled:true description: "防止垃圾评论和刷赞行为"
7.2 突发流量应对

营销活动期间

// 通过API动态调整规则 POST /api/firewall/rules { "ruleName": "秒杀活动保护", "apiPattern": "/api/seckill/**", "qpsLimit": 1000, "userLimit": 1, "timeWindow": 60, "enabled": true, "description": "秒杀活动期间特殊限制" }

爬虫防护

// 手动添加黑名单示例 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 部署

FROM openjdk:11-jre-slim VOLUME /tmp COPY target/springboot-firewall-1.0.jar app.jar EXPOSE 8080 ENTRYPOINT ["java","-jar","/app.jar"]

监控集成

# Prometheus 监控指标 management: metrics: tags: application: firewall export: prometheus: enabled: true

总结

本文实现了一个基于 SpringBoot 的轻量级 API 防火墙,通过拦截器机制提供实时防护能力。

系统采用 Guava Cache 实现高性能内存缓存,支持 QPS 限制和用户访问频率控制。

提供了完整的黑白名单管理功能,配备现代化的 Web 管理界面,支持规则的在线配置和实时生效。整体架构简洁高效,适合中小型项目快速集成使用。

https://github.com/yuboon/java-examples/tree/master/springboot-firewall


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,长按”或“扫描”下方二维码噢

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

文章有帮助的话,在看,转发吧。 谢谢支持哟 (*^__^*)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询