feat(gateway): 应用级免签(ANON) + 签名限流/per-route 超时 + 代理测试页
build / build-push (push) Successful in 1m47s

- open_api_app 表(docs/sql/04_app.sql) + OpenApiApp/OpenApiAppRepository/AppAuthRegistry:
  authMode=ANON 应用级免签,支持 '*' 路径通配窗口,有效期 ≤31 天惰性到期;
  PUT 带 authMode=ANON 时 expireAt 必传
- SignedRateLimiter + RateLimitFilter:按签名键限流(fail-closed);
  RouteSpec 增加 per-route 超时与请求体积上限,StreamingForwarder 执行超时
- ProxyTestController:网关代理测试页后端接口
- SignVerifyFilter/DispatchFilter/InternalAdminController 及对应测试接线
- .gitignore 补 gateway-run.log / tmp_*.sql(本地运行产物不入库)

验证:全量 171 用例绿 + 双轮冒烟(2026-10-03)
This commit is contained in:
chenxing
2026-10-09 10:37:42 +08:00
parent 48625d0f11
commit 1ae94d7100
31 changed files with 2164 additions and 43 deletions
+29
View File
@@ -0,0 +1,29 @@
-- =====================================================================
-- 开放接口中心 应用治理表 open_api_app(应用级免签 C 方向,G1)
-- 语义:按调用方应用(appKey)维度登记治理属性——只管"免签与否",不管密钥;
-- 密钥链(appauth starter Redis sign:app:{appKey})职责不变,SIGNED 应用照旧从那里取 secret,
-- ANON 应用不要求密钥存在(免签应用可无密钥)。
-- 判定:表空 / 无行 / 禁用 / 过期 = 一律维持验签(fail-closed 缺省,存量 appKey 零行为变化);
-- auth_mode=ANON 的行仅内部入口免签(免 X-Timestamp/X-Signature 两头,仍须带 X-App-Key),
-- 到期判定是惰性的(AppAuthRegistry.admit 实时比对 expire_at,零定时任务),
-- 过期行即刻不再命中(等价恢复验签),行数据不清除,想再用走治理页续期(重新起算 ≤31 天)。
-- 哨兵:app_key='*' = 匿名窗口行(uk 保证全局至多一行)——内部入口无 X-App-Key 的请求也放行,
-- 强制生效周期 ≤31 天(O1 决议);该行只折算成"窗口到期时刻",不进 appKey 映射。
-- 操作注意:ANON 应用改回 SIGNED 前,须先确认密钥链有该 appKey 的键,否则即刻 401。
-- 写入方:治理面 API(/api/internal/admin/apps,保存后就地 reload + 广播)或手工 SQL;
-- 网关运行时只读,改行后热重载即生效(不重启)。
-- 可重复执行:CREATE TABLE IF NOT EXISTS(不 DROP——治理数据不可丢)
-- =====================================================================
CREATE TABLE IF NOT EXISTS open_api_app (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
app_key VARCHAR(64) NOT NULL COMMENT '调用方 appKey(与密钥链 sign:app:{appKey} 同键;ANON 应用无须密钥;*=匿名窗口行(内部入口无票据放行,至多一行)',
app_name VARCHAR(64) COMMENT '展示名(可选)',
auth_mode VARCHAR(16) NOT NULL DEFAULT 'SIGNED' COMMENT 'SIGNED=验签(缺省)/ANON=内部入口免签',
expire_at DATETIME COMMENT '免签生效到期(ANON 行必填,保存时校验 ≤31 天;过期=惰性恢复验签;SIGNED 行为 NULL)',
enabled TINYINT NOT NULL DEFAULT 1,
remark VARCHAR(256),
gmt_create DATETIME NOT NULL,
gmt_modified DATETIME NOT NULL,
UNIQUE KEY uk_app (app_key)
);