系统级请求接口 IP 频率限制管理(登录+全局接口限流)

以下是针对 “系统级请求接口 IP 频率限制管理(登录+全局接口限流)” 的完整设计方案,满足你所有要求(不依赖 Redis、纯 DB 实现、业界合理阈值、多维度限流、管理员可管理、用户不可见、风格严格符合现有规范)。

一、限流策略(业界公认合理阈值,初期写死)

维度 阈值(普通用户) 阈值(已触发过限流的恶意IP) 说明
每分钟 30 次 5 次 防止暴力破解、刷接口
每小时 300 次 30 次 正常用户不可能短时打这么高
每天 3000 次 200 次 进一步压制已列入观察名单的IP
全局封禁 手动或连续3次触发高级限流 管理员永久封禁

触发任一维度 → 记录到 ip_rate_limit_log 表,并进入“恶意IP观察名单”,后续自动收紧阈值。

二、数据库表设计(两张表)

1. ip_rate_limit_config(IP限流配置白名单/黑名单,管理员维护)

CREATE TABLE `ip_rate_limit_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `ip` varchar(45) NOT NULL COMMENT 'IPv4/IPv6/CIDR,如 192.168.1.1 或 192.168.1.0/24',
  `type` tinyint(4) NOT NULL COMMENT '1=白名单(完全不限制) 2=黑名单(永久封禁) 3=恶意观察(收紧阈值)',
  `reason` varchar(255) DEFAULT NULL COMMENT '封禁/观察原因',
  `expire_time` datetime(3) DEFAULT NULL COMMENT '临时封禁到期时间,NULL表示永久',
  `status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1=启用 0=禁用',
  `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  `creator_id` bigint(20) DEFAULT NULL,
  `updater_id` bigint(20) DEFAULT NULL,
  `delete_flag` tinyint(4) NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_ip` (`ip`,`delete_flag`),
  KEY `idx_type_status` (`type`,`status`,`delete_flag`),
  KEY `idx_expire` (`expire_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP限流配置表';

2. ip_rate_limit_log(每次触发限流详细记录)

CREATE TABLE `ip_rate_limit_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `ip` varchar(45) NOT NULL,
  `uri` varchar(255) NOT NULL COMMENT '请求路径',
  `method` varchar(10) NOT NULL COMMENT 'GET/POST等',
  `user_id` bigint(20) DEFAULT NULL COMMENT '登录用户ID,未登录为NULL',
  `username` varchar(64) DEFAULT NULL COMMENT '登录用户名,未登录为NULL',
  `trigger_level` tinyint(4) NOT NULL COMMENT '1=分钟 2=小时 3=天 4=全局封禁',
  `trigger_count` int NOT NULL COMMENT '触发时该维度的累计次数',
  `client_info` varchar(512) DEFAULT NULL COMMENT 'User-Agent + 其他Header摘要',
  `status` tinyint(4) NOT NULL DEFAULT 1,
  `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  `creator_id` bigint(20) DEFAULT NULL,
  `updater_id` bigint(20) DEFAULT NULL,
  `delete_flag` tinyint(4) NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  KEY `idx_ip_create` (`ip`,`create_time`),
  KEY `idx_uri` (`uri`),
  KEY `idx_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP触发限流日志表';

三、SQL 迁移脚本(db/migrate 目录)

-- V20251127_01__create_ip_rate_limit_tables.sql
CREATE TABLE `ip_rate_limit_config` (
  -- 字段同上
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP限流配置表';

CREATE TABLE `ip_rate_limit_log` (
  -- 字段同上
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IP触发限流日志表';

-- 初始化几个常见内网白名单
INSERT INTO `ip_rate_limit_config` (ip, type, reason, status, creator_id)
VALUES ('127.0.0.1', 1, '本地开发', 1, 1),
       ('10.0.0.0/8', 1, '内网', 1, 1),
       ('172.16.0.0/12', 1, '内网', 1, 1),
       ('192.168.0.0/16', 1, '内网', 1, 1);

四、后端骨架(Spring Boot + MyBatis,手动写 get/set,禁止 lombok)

1. 全局拦截器(核心限流逻辑) - IpRateLimitInterceptor

@Component
public class IpRateLimitInterceptor implements HandlerInterceptor {

    @Autowired private IpRateLimitService ipRateLimitService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ip = IpUtils.getRealIp(request);
        String uri = request.getRequestURI();
        String method = request.getMethod();

        // 1. 先查白名单/黑名单
        if (ipRateLimitService.isWhiteIp(ip) || ipRateLimitService.isBlackIp(ip)) {
            return true; // 白名单直接放行,黑名单后续统一返回403
        }

        // 2. 计数 + 判断是否触发
        RateLimitResult result = ipRateLimitService.checkAndRecord(ip, uri, method, getCurrentUserId());
        if (!result.isAllow()) {
            // 写触发日志
            ipRateLimitService.recordTriggerLog(ip, uri, method, getCurrentUserId(), result);
            ResponseUtil.writeJson(response, Result.error(429, "请求过于频繁,请稍后再试"));
            return false;
        }
        return true;
    }
}

2. Service 关键方法(纯数据库实现)

@Service
public class IpRateLimitService {

    // 判断是否白名单、黑名单
    public boolean isWhiteIp(String ip);
    public boolean isBlackIp(String ip);

    // 核心检查方法(返回是否允许 + 触发了哪个级别)
    public RateLimitResult checkAndRecord(String ip, String uri, String method, Long userId);

    // 写入触发日志
    public void recordTriggerLog(String ip, String uri, String method, Long userId, RateLimitResult result);
}

3. 后端 Controller 拆分(严格按视角拆分)

// 管理员专用
@AdminController("/admin/ip-rate-limit")
public class AdminIpRateLimitController {
    // 配置表增删改查 + 封禁/解禁
    GET  /config/list
    POST /config/save
    POST /config/ban      // 手动封禁IP
    POST /config/unban

    // 触发日志查询
    GET  /log/list
}

// 普通用户完全看不到任何接口

4. Mapper XML 示例(注意转义 < >)

<select id="countByMinute" resultType="long">
    SELECT COUNT(1)
    FROM some_request_log_table
    WHERE ip = #{ip}
      AND create_time >= DATE_SUB(NOW(3), INTERVAL 1 MINUTE)
</select>

五、前端 Vue3 管理页面(仅管理员可见)

路径:/admin/ip-rate-limit

1. 页面拆分(组件化)

src/views/admin/ip-rate-limit/
├── Index.vue                <-- 主入口(Tab切换)
├── components/
│   ├── ConfigList.vue       <-- IP配置列表 + 封禁按钮
│   ├── ConfigFormDrawer.vue <-- 新增/编辑抽屉
│   ├── TriggerLogTable.vue  <-- 触发日志表格(支持按IP/路径筛选)
│   └── IpSearchInput.vue    <-- 全局IP搜索组件(可复用)

2. 交互设计

  • 顶部搜索栏:支持按 IP、状态(白/黑/观察)、到期时间筛选
  • 操作列:
    • 白名单 → 移除
    • 观察名单 → 升级为永久封禁 / 解除观察
    • 黑名单 → 解禁
  • 触发日志页支持导出 CSV
  • 所有请求走 /admin/ip-rate-limit/** 网关权限拦截

六、数据初始化(测试用)

-- 模拟几个恶意IP
INSERT INTO ip_rate_limit_config (ip, type, reason, status, creator_id)
VALUES ('182.11.22.33', 3, '频繁登录失败', 1, 1),
       ('185.44.55.66', 2, 'CC攻击', 1, 1);

七、后续可扩展点(已预留)

  1. 后期想换成 Redis 令牌桶/漏桶,只需改 IpRateLimitService 实现类即可,对外接口不变
  2. 支持按 userId + ip 双维度限流(防多开刷)
  3. 支持不同接口不同阈值(后续加张 uri_config 表)

完全满足你所有要求:不依赖Redis、纯DB、阈值合理、管理员可视化管理、用户不可见、风格严格合规、可维护性高。需要的代码骨架和SQL都已给出,可直接落地。

接口级别拓展

升级版设计:完全可配置 + 支持按接口(URI)单独指定限流策略
完全抛弃代码写死,所有阈值、开关、收紧倍数全部走 sys_kv_config + 新增一张「接口限流规则表」,做到零代码改动即可在线调整任意接口的限流力度

一、全局默认限流策略(放入 sys_kv_config)

config_key config_value config_name description 默认值
rate_limit.enable true 是否开启IP限流 总开关 true
rate_limit.normal.minute 30 普通IP - 每分钟最大请求   30
rate_limit.normal.hour 300 普通IP - 每小时最大请求   300
rate_limit.normal.day 3000 普通IP - 每天最大请求   3000
rate_limit.malicious.minute 5 恶意IP - 每分钟最大请求 已触发过限流的IP自动收紧 5
rate_limit.malicious.hour 30 恶意IP - 每小时最大请求   30
rate_limit.malicious.day 200 恶意IP - 每天最大请求   200
rate_limit.malicious.auto_add_days 7 自动加入恶意观察名单天数 触发任意一级限流后自动观察N天 7
rate_limit.malicious.trigger_times_to_black 3 触发N次后自动永久封禁 观察期内再次触发N次 → 自动黑名单 3
rate_limit.block.duration_minutes 30 被限流后封禁多久(分钟) 返回429后客户端多久才能再访问 30

初始化脚本(一次性执行)

-- V20251128_01__init_rate_limit_global_config.sql
INSERT INTO sys_kv_config (config_key, config_value, config_name, description, status, creator_id) VALUES
('rate_limit.enable', 'true', '是否开启IP限流', '总开关,关闭后所有接口都不再限流', 1, 1),
('rate_limit.normal.minute', '30', '普通IP - 每分钟最大请求', '', 1, 1),
('rate_limit.normal.hour', '300', '普通IP - 每小时最大请求', '', 1, 1),
('rate_limit.normal.day', '3000', '普通IP - 每天最大请求', '', 1, 1),
('rate_limit.malicious.minute', '5', '恶意IP - 每分钟最大请求', '已触发过限流的IP收紧阈值', 1, 1),
('rate_limit.malicious.hour', '30', '恶意IP - 每小时最大请求', '', 1, 1),
('rate_limit.malicious.day', '200', '恶意IP - 每天最大请求', '', 1, 1),
('rate_limit.malicious.auto_add_days', '7', '自动加入恶意观察名单天数', '', 1, 1),
('rate_limit.malicious.trigger_times_to_black', '3', '观察期内再次触发N次自动永久封禁', '', 1, 1),
('rate_limit.block.duration_minutes', '30', '被限流后封禁多久(分钟', '客户端看到429后多久可以再试', 1, 1);

二、新增表:接口单独限流规则(覆盖全局)

-- ip_rate_limit_uri_rule  接口级别限流规则(优先级最高)
CREATE TABLE `ip_rate_limit_uri_rule` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `uri_pattern` varchar(255) NOT NULL COMMENT 'Ant风格路径,例如 /api/login/**   /api/pay/**',
  `method` varchar(10) DEFAULT '*' COMMENT 'HTTP方法,* 表示全部,多个用逗号分隔',
  `enable_minute_limit` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否开启分钟限流',
  `minute_limit` int DEFAULT NULL COMMENT '自定义每分钟次数,NULL=使用全局',
  `enable_hour_limit` tinyint(1) NOT NULL DEFAULT 1,
  `hour_limit` int DEFAULT NULL,
  `enable_day_limit` tinyint(1) NOT NULL DEFAULT 1,
  `day_limit` int DEFAULT NULL,
  `description` varchar(255) DEFAULT NULL COMMENT '规则说明',
  `status` tinyint(4) NOT NULL DEFAULT 1,
  `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
  `creator_id` bigint(20) DEFAULT NULL,
  `updater_id` bigint(20) DEFAULT NULL,
  `delete_flag` tinyint(4) NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_uri_pattern_method` (`uri_pattern`,`method`,`delete_flag`),
  KEY `idx_status` (`status`,`delete_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='接口单独限流规则表';

常用规则示例(初始化数据)

INSERT INTO ip_rate_limit_uri_rule (uri_pattern, method, minute_limit, hour_limit, day_limit, description, status, creator_id) VALUES
('/api/auth/login',            '*',    10,   60,    500,   '登录接口严格限制,防暴力破解', 1, 1),
('/api/auth/sms-code',         '*',     5,   20,    100,   '短信验证码接口', 1, 1),
('/api/pay/**',                 '*',    20,  200,   2000,   '支付相关接口', 1, 1),
('/api/admin/**',               '*',  NULL, NULL,  NULL,   '后台接口使用全局默认', 1, 1),
('/api/open/**',                '*',    100, 1000, 10000,   '开放接口放宽', 1, 1);

三、最终限流判断优先级(代码里这样写)

// 1. 黑名单 → 直接拒绝
// 2. 白名单 → 直接放行
// 3. 查询 ip_rate_limit_uri_rule 是否命中当前 uri+method
//     → 有命中 → 使用该规则的 minute/hour/day(NULL 则回落全局)
//     → 没命中 → 使用全局默认阈值
// 4. 查询该IP是否在“恶意观察名单”
//     → 是 → 使用 malicious.* 阈值
//     → 否 → 使用 normal.* 阈值

四、管理员后台新增页面(Vue3)

路径:/admin/system/rate-limit

<!-- 三个 Tab -->
1. 全局限流配置      → 直接编辑 sys_kv_config 表对应条目(实时生效)
2. 接口限流规则      → ip_rate_limit_uri_rule 增删改查 + AntPath 测试工具
3. IP黑白名单管理    → 原来的 ip_rate_limit_config 表
4. 触发日志          → ip_rate_limit_log 查询 + 导出

五、Service 核心伪代码(体现优先级)

public RateLimitResult checkAndRecord(String ip, String uri, String method, Long userId) {
    // 1. 黑白名单快速返回
    if (isBlackIp(ip)) return blockForever();
    if (isWhiteIp(ip)) return allow();

    // 2. 查找接口专属规则
    UriRule rule = uriRuleMapper.selectByUriAndMethod(uri, method);

    // 3. 组装当前生效阈值
    Threshold t = new Threshold();
    t.minute = getValue(rule?.getMinuteLimit(), globalNormalMinute);
    t.hour   = getValue(rule?.getHourLimit(),   globalNormalHour);
    t.day    = getValue(rule?.getDayLimit(),    globalNormalDay);

    // 4. 如果是恶意IP,全部再收紧
    if (isMaliciousIp(ip)) {
        t.minute = Math.min(t.minute, globalMaliciousMinute);
        t.hour   = Math.min(t.hour,   globalMaliciousHour);
        t.day    = Math.min(t.day,    globalMaliciousDay);
    }

    // 5. 数据库计数(三条SQL分别查最近1分钟、1小时、24小时)
    long cntMin = countLastMinutes(ip, uri, 1);
    long cntHour = countLastHours(ip, uri, 1);
    long cntDay = countLastHours(ip, uri, 24);

    // 6. 判断是否触发
    if (cntMin >= t.minute || cntHour >= t.hour || cntDay >= t.day) {
        autoAddToMaliciousIfNeeded(ip);        // 自动加入观察名单
        autoUpgradeToBlackIfNeeded(ip);        // 触发次数达标自动永久封禁
        return block(t.blockMinutes);
    }

    // 7. 正常请求也要记录,用于后续统计
    requestLogMapper.insert(ip, uri, method, userId);
    return allow();
}

六、总结优势

  • 所有阈值 100% 在线可调,零重启
  • 重点接口(如登录、短信、支付)可以单独严格限制
  • 普通接口继续走合理默认值,对用户几乎无感知
  • 恶意IP自动收紧 + 自动升级黑名单,全程无需人工介入
  • 完全兼容你现有 sys_kv_config 体系,无需新加配置中心

这样就做到真正「企业级、可运维、可观测、可调参」的系统级IP频率限制了。