Administrator
3 hours ago decc54295e117b082ac0fae89f8578a17271196c
src/main/java/cc/mrbird/febs/firewall/service/impl/FirewallRuleServiceImpl.java
@@ -5,9 +5,12 @@
import cc.mrbird.febs.common.utils.RedisUtils;
import cc.mrbird.febs.firewall.dto.CountryVo;
import cc.mrbird.febs.firewall.entity.FirewallCountryRule;
import cc.mrbird.febs.firewall.entity.FirewallIpWhite;
import cc.mrbird.febs.firewall.entity.FirewallSite;
import cc.mrbird.febs.firewall.mapper.FirewallCountryRuleMapper;
import cc.mrbird.febs.firewall.mapper.FirewallIpWhiteMapper;
import cc.mrbird.febs.firewall.mapper.FirewallSiteMapper;
import cc.mrbird.febs.firewall.nginx.IpWhitelistNginxConfigGenerator;
import cc.mrbird.febs.firewall.nginx.NginxConfigGenerator;
import cc.mrbird.febs.firewall.service.IFirewallRuleService;
import cn.hutool.core.util.StrUtil;
@@ -34,8 +37,10 @@
public class FirewallRuleServiceImpl implements IFirewallRuleService {
    private final FirewallCountryRuleMapper countryRuleMapper;
    private final FirewallIpWhiteMapper ipWhiteMapper;
    private final FirewallSiteMapper siteMapper;
    private final NginxConfigGenerator generator;
    private final IpWhitelistNginxConfigGenerator ipWhitelistGenerator;
    private final RedisUtils redisUtils;
    /** Redis 中 Nginx reload 任务队列 key */
@@ -88,10 +93,14 @@
        // 删除站点关联的国家规则
        countryRuleMapper.delete(new LambdaQueryWrapper<FirewallCountryRule>()
                .eq(FirewallCountryRule::getSiteId, id));
        // 删除Nginx配置文件
        // 删除站点关联的IP白名单
        ipWhiteMapper.delete(new LambdaQueryWrapper<FirewallIpWhite>()
                .eq(FirewallIpWhite::getSiteId, id));
        // 删除Nginx配置文件(国家黑名单 + IP白名单)
        if (StrUtil.isNotBlank(site.getNginxConf())) {
            cn.hutool.core.io.FileUtil.del(site.getNginxConf());
        }
        cn.hutool.core.io.FileUtil.del(IpWhitelistNginxConfigGenerator.getConfPath(id));
        siteMapper.deleteById(id);
        log.info("防火墙站点已删除: id={}, name={}", id, site.getSiteName());
        return new FebsResponse().success().message("删除成功");
@@ -163,6 +172,7 @@
    private void regenerateNginxConfig(Long siteId) {
        try {
            generator.generate(siteId);
            ipWhitelistGenerator.generate(siteId);
            redisUtils.lSet(NGINX_RELOAD_QUEUE_KEY, String.valueOf(siteId));
            log.info("Nginx reload 信号已入队: siteId={}", siteId);
        } catch (Exception e) {
@@ -211,6 +221,7 @@
        // 3. 生成 Nginx 配置文件
        generator.generate(siteId);
        ipWhitelistGenerator.generate(siteId);
        // 4. 发送 reload 信号
        redisUtils.lSet(NGINX_RELOAD_QUEUE_KEY, String.valueOf(siteId));
@@ -220,7 +231,71 @@
    @Override
    public void triggerNginxReload(Long siteId) {
        generator.generate(siteId);
        ipWhitelistGenerator.generate(siteId);
        redisUtils.lSet(NGINX_RELOAD_QUEUE_KEY, String.valueOf(siteId));
        log.info("手动触发 Nginx reload: siteId={}", siteId);
    }
    // ==================== IP白名单管理 ====================
    @Override
    public IPage<FirewallIpWhite> ipWhiteList(FirewallIpWhite ipWhite, QueryRequest request) {
        Page<FirewallIpWhite> page = new Page<>(request.getPageNum(), request.getPageSize());
        LambdaQueryWrapper<FirewallIpWhite> wrapper = new LambdaQueryWrapper<FirewallIpWhite>()
                .eq(ipWhite.getSiteId() != null, FirewallIpWhite::getSiteId, ipWhite.getSiteId())
                .eq(ipWhite.getEnabled() != null, FirewallIpWhite::getEnabled, ipWhite.getEnabled())
                .like(StrUtil.isNotBlank(ipWhite.getIp()), FirewallIpWhite::getIp, ipWhite.getIp())
                .like(StrUtil.isNotBlank(ipWhite.getRemark()), FirewallIpWhite::getRemark, ipWhite.getRemark())
                .orderByDesc(FirewallIpWhite::getCreatedTime);
        return ipWhiteMapper.selectPage(page, wrapper);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FebsResponse saveIpWhite(FirewallIpWhite ipWhite) {
        if (ipWhite.getSiteId() == null) {
            return new FebsResponse().fail().message("请选择站点");
        }
        if (StrUtil.isBlank(ipWhite.getIp())) {
            return new FebsResponse().fail().message("IP地址不能为空");
        }
        ipWhite.setIp(ipWhite.getIp().trim());
        if (ipWhite.getId() != null) {
            ipWhiteMapper.updateById(ipWhite);
            log.info("防火墙IP白名单已更新: id={}, siteId={}, ip={}", ipWhite.getId(), ipWhite.getSiteId(), ipWhite.getIp());
        } else {
            // 检查同站点下是否已存在相同IP
            Integer count = ipWhiteMapper.selectCount(new LambdaQueryWrapper<FirewallIpWhite>()
                    .eq(FirewallIpWhite::getSiteId, ipWhite.getSiteId())
                    .eq(FirewallIpWhite::getIp, ipWhite.getIp()));
            if (count > 0) {
                return new FebsResponse().fail().message("该站点下已存在相同IP: " + ipWhite.getIp());
            }
            ipWhiteMapper.insert(ipWhite);
            log.info("防火墙IP白名单已新增: siteId={}, ip={}", ipWhite.getSiteId(), ipWhite.getIp());
        }
        // 保存后自动生成Nginx配置并发送reload信号
        ipWhitelistGenerator.generate(ipWhite.getSiteId());
        redisUtils.lSet(NGINX_RELOAD_QUEUE_KEY, String.valueOf(ipWhite.getSiteId()));
        return new FebsResponse().success().message("保存成功,Nginx 配置已更新");
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FebsResponse deleteIpWhite(Long id) {
        FirewallIpWhite ipWhite = ipWhiteMapper.selectById(id);
        if (ipWhite == null) {
            return new FebsResponse().fail().message("IP白名单不存在");
        }
        Long siteId = ipWhite.getSiteId();
        ipWhiteMapper.deleteById(id);
        log.info("防火墙IP白名单已删除: id={}, siteId={}, ip={}", id, siteId, ipWhite.getIp());
        // 删除后自动生成Nginx配置并发送reload信号
        ipWhitelistGenerator.generate(siteId);
        redisUtils.lSet(NGINX_RELOAD_QUEUE_KEY, String.valueOf(siteId));
        return new FebsResponse().success().message("删除成功,Nginx 配置已更新");
    }
}