From aeb0696f457ca85b62d15ab6586c5779cf5cd97b Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Fri, 31 Jul 2026 16:56:21 +0800
Subject: [PATCH] feat(firewall): 添加访问日志功能

---
 src/main/java/cc/mrbird/febs/firewall/nginx/IpWhitelistNginxConfigGenerator.java |  126 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 126 insertions(+), 0 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/firewall/nginx/IpWhitelistNginxConfigGenerator.java b/src/main/java/cc/mrbird/febs/firewall/nginx/IpWhitelistNginxConfigGenerator.java
new file mode 100644
index 0000000..2d1ff51
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/firewall/nginx/IpWhitelistNginxConfigGenerator.java
@@ -0,0 +1,126 @@
+package cc.mrbird.febs.firewall.nginx;
+
+import cc.mrbird.febs.firewall.entity.FirewallIpWhite;
+import cc.mrbird.febs.firewall.entity.FirewallSite;
+import cc.mrbird.febs.firewall.mapper.FirewallIpWhiteMapper;
+import cc.mrbird.febs.firewall.mapper.FirewallSiteMapper;
+import cn.hutool.core.io.FileUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Nginx IP白名单配置文件生成器
+ * <p>
+ * 白名单模式:如果表中有启用的IP记录,则仅允许这些IP访问;表为空则放行所有IP。
+ * <p>
+ * 输出文件: /etc/nginx/conf.d/firewall_ipwhite_{siteId}.conf
+ *
+ * @author auto-generated
+ * @date 2026-07-31
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class IpWhitelistNginxConfigGenerator {
+
+    private final FirewallIpWhiteMapper ipWhiteMapper;
+    private final FirewallSiteMapper siteMapper;
+
+    /** Nginx 配置目录 */
+    private static final String NGINX_CONF_DIR = "/etc/nginx/conf.d/";
+    /** 配置文件前缀 */
+    private static final String CONF_PREFIX = "firewall_ipwhite_";
+
+    /**
+     * 生成 IP 白名单 map 配置
+     * <pre>
+     * # 有白名单IP时:
+     * map $remote_addr $allow_ip_1 {
+     *     default 0;
+     *     1.2.3.4 1;
+     *     5.6.7.8 1;
+     * }
+     *
+     * # 无白名单IP时:
+     * map $remote_addr $allow_ip_1 {
+     *     default 1;
+     * }
+     * </pre>
+     * 有IP时 default 0(默认拒绝,仅白名单放行);
+     * 无IP时 default 1(全部放行)。
+     * <p>
+     * Nginx 中判断: if ($allow_ip_1 = 0) { return 403; }
+     *
+     * @param siteId 站点ID
+     */
+    public void generate(Long siteId) {
+        FirewallSite site = siteMapper.selectById(siteId);
+        if (site == null) {
+            log.warn("防火墙站点不存在: siteId={}", siteId);
+            return;
+        }
+
+        // 查询站点下所有启用的白名单IP(未过期或永久有效)
+        List<FirewallIpWhite> ipList = ipWhiteMapper.selectList(
+                new LambdaQueryWrapper<FirewallIpWhite>()
+                        .eq(FirewallIpWhite::getSiteId, siteId)
+                        .eq(FirewallIpWhite::getEnabled, 1)
+                        .and(w -> w.isNull(FirewallIpWhite::getExpireTime)
+                                    .or().gt(FirewallIpWhite::getExpireTime, new Date()))
+        );
+
+        boolean hasIps = !ipList.isEmpty();
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("# Firewall IP Whitelist Map\n");
+        sb.append("# Site: ").append(site.getSiteName()).append(" (").append(site.getDomain()).append(")\n");
+        sb.append("# Generated at: ").append(new Date()).append("\n");
+        sb.append("# Total IPs: ").append(ipList.size()).append("\n");
+        sb.append("# Whitelist active: ").append(hasIps).append("\n\n");
+
+        // 标记变量:白名单是否生效(有IP记录=1,无记录=0)
+        // 用 map 模拟,使变量在 http 级别可用
+        sb.append("# 是否启用白名单模式: ").append(hasIps ? "1=是" : "0=否").append("\n");
+        sb.append("map $host $ipwh_active_").append(siteId).append(" {\n");
+        sb.append("    default ").append(hasIps ? "1" : "0").append(";\n");
+        sb.append("}\n\n");
+
+        sb.append("map $remote_addr $allow_ip_").append(siteId).append(" {\n");
+        if (!hasIps) {
+            // 无白名单 → 全部放行
+            sb.append("    default 1;\n");
+        } else {
+            // 有白名单 → 默认拒绝,仅白名单IP放行
+            sb.append("    default 0;\n");
+            for (FirewallIpWhite ip : ipList) {
+                sb.append("    ").append(ip.getIp()).append(" 1;\n");
+            }
+        }
+        sb.append("}\n");
+
+        // 确定配置文件路径
+        String confFileName = NGINX_CONF_DIR + CONF_PREFIX + siteId + ".conf";
+        File confFile = new File(confFileName);
+        try {
+            FileUtil.writeString(sb.toString(), confFile, StandardCharsets.UTF_8);
+            log.info("Nginx IP白名单配置已生成: {}, 白名单IP数: {}", confFile.getAbsolutePath(), ipList.size());
+        } catch (Exception e) {
+            log.error("Nginx IP白名单配置文件写入失败: path={}", confFile.getAbsolutePath(), e);
+            throw new RuntimeException("Nginx IP白名单配置文件写入失败: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 获取 IP 白名单配置文件路径
+     */
+    public static String getConfPath(Long siteId) {
+        return NGINX_CONF_DIR + CONF_PREFIX + siteId + ".conf";
+    }
+}

--
Gitblit v1.9.1