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/NginxConfigGenerator.java |   93 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 93 insertions(+), 0 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/firewall/nginx/NginxConfigGenerator.java b/src/main/java/cc/mrbird/febs/firewall/nginx/NginxConfigGenerator.java
new file mode 100644
index 0000000..661b82b
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/firewall/nginx/NginxConfigGenerator.java
@@ -0,0 +1,93 @@
+package cc.mrbird.febs.firewall.nginx;
+
+import cc.mrbird.febs.firewall.entity.FirewallSite;
+import cc.mrbird.febs.firewall.mapper.FirewallCountryRuleMapper;
+import cc.mrbird.febs.firewall.mapper.FirewallSiteMapper;
+import cn.hutool.core.io.FileUtil;
+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.List;
+
+/**
+ * Nginx 国家黑名单配置文件生成器
+ * <p>
+ * 默认放行所有国家,仅拦截配置中选中的国家(黑名单模式)。
+ * <p>
+ * 输出文件: /etc/nginx/conf.d/firewall_country_{siteId}.conf
+ * <p>
+ * 不直接执行 reload,仅负责文件生成。
+ * reload 由 NginxReloadTask 消费 Redis 队列后执行,防止误操作。
+ *
+ * @author auto-generated
+ * @date 2026-07-31
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class NginxConfigGenerator {
+
+    private final FirewallCountryRuleMapper mapper;
+    private final FirewallSiteMapper siteMapper;
+
+    /** Nginx 配置目录 */
+    private static final String NGINX_CONF_DIR = "/etc/nginx/conf.d/";
+    /** 配置文件前缀 */
+    private static final String CONF_PREFIX = "firewall_country_";
+
+    /**
+     * 生成 Nginx 国家黑名单 map 配置
+     * <pre>
+     * map $geoip_country_code $allow_country {
+     *     default 1;
+     *     JP 0;
+     *     US 0;
+     * }
+     * </pre>
+     * default 1 表示默认放行,列表中国家设为 0 表示拦截。
+     * Nginx 中判断: if ($allow_country_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;
+        }
+
+        List<String> countries = mapper.selectEnableCountry(siteId);
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("# Firewall Country Block Map (Blacklist)\n");
+        sb.append("# Site: ").append(site.getSiteName()).append(" (").append(site.getDomain()).append(")\n");
+        sb.append("# Generated at: ").append(new java.util.Date()).append("\n\n");
+        sb.append("map $geoip_country_code $allow_country_").append(siteId).append(" {\n");
+        sb.append("    default 1;\n");
+
+        for (String c : countries) {
+            sb.append("    ").append(c.toUpperCase()).append(" 0;\n");
+        }
+
+        sb.append("}\n");
+
+        // 写入文件
+        String confFileName = site.getNginxConf();
+        if (confFileName == null || confFileName.isEmpty()) {
+            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 黑名单配置已生成: {}, 拦截国家: {}", confFile.getAbsolutePath(), countries);
+        } catch (Exception e) {
+            log.error("Nginx 配置文件写入失败: path={}", confFile.getAbsolutePath(), e);
+            throw new RuntimeException("Nginx 配置文件写入失败: " + e.getMessage(), e);
+        }
+    }
+}

--
Gitblit v1.9.1