chenxing
|
a2c8905c7a
|
对接规范§3:外观偏好同源读端点 /api/appearance(自建同构哑管道,503铁律,回环验签链 userbase→userhome,env OPENGW_APPEARANCE_APP_KEY 点燃)
build / build-push (push) Successful in 2m11s
|
2026-10-11 21:58:54 +08:00 |
|
chenxing
|
7e3690e523
|
feat(sso): 治理面 CAS 登录 + 机器面内部令牌门 + 注册表重载双口
build / build-push (push) Successful in 48s
- 治理面浏览器 SSO(/api/internal/admin/*):cas-client-core 3.5.1 固定 service 票据校验
(ctx 为空、外链前缀由 Caddy 剥离,按请求路径拼 service 必 404,故用固定回跳靶点);
未登录双形态应答——带 yschapirequest:1 出 200+{code:302,urlToRedirectTo}(平台同构,
alova 直接整页跳),裸调用出 401 治理面信封;OPENGW_SSO_ENABLED 默认关,
回滚=清 env 重新 Apply,不回退镜像
- 机器面(/api/internal/* 其余)收口 InternalTokenFilter:只认 X-Internal-Token,
值走 OPENGW_INTERNAL_TOKEN env,空=灰度放行(projman 路由同步不打断);
比较用 XOR 折叠常量时间(String.equals 提前短路有时序侧信道;MessageDigest.isEqual
在 JDK8 非 const-time,JDK9 才修)
- 注册表重载抽 RegistryReloader:机器面 /routes/refresh 与控制台按钮
/admin/routes/reload 共用同一实现(一接口面一种认证,不做令牌 OR 会话混判)
- 治理会话 cookie 改名 OPENGW_SESSION:ctx 为空时默认 JSESSIONID(Path=/) 会与
base 域各应用同名叠放进同一个 Cookie 头
- session 端点在 CAS 面未装配时回空 ssoHost:前端据此隐藏「退出」,不在匿名端点
泄漏 CAS 基址、灰度期不出现平台级注销入口
- 新增 44 用例:面守卫机械钉桩(全仓控制器映射必须声明鉴权归属)+ 装配红线
(默认关/序位/固定 service 原样采用)+ 双形态应答 + 令牌三态/灰度窗 + 重载器
|
2026-10-11 12:46:55 +08:00 |
|
chenxing
|
1ae94d7100
|
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)
|
2026-10-09 10:37:42 +08:00 |
|
chenxing
|
48625d0f11
|
fix(gateway): 修复 RouteChangeBroadcaster 的 Redis 注入歧义(线上启动崩溃)
build / build-push (push) Successful in 1m1s
线上 f456c857 启动失败、容器无限重启,根因为 StringRedisTemplate 注入歧义:
- Field redisTemplate in RouteChangeBroadcaster required a single bean, but 2 were found:
stringRedisTemplate (RedisAutoConfiguration) 与
signKeyStringRedisTemplate (yh-appauth SignKeyRedisAutoConfiguration)
修复:
- 显式 @Qualifier("stringRedisTemplate") 绑定应用主库模板。必须选主库:网关
SPRING_REDIS_DATABASE=7,而 appauth 密钥模板直连 db0——选错会造成发布/订阅异库、
广播静默失效,比启动失败更难排查。
- 订阅容器改用 redisTemplate.getConnectionFactory(),结构上保证发布与订阅同库,
同时消除 RedisConnectionFactory 同类型多 bean 的隐患。
回归测试 RouteChangeBroadcasterWiringTest(3 例):
- 手工驱动 AutowiredAnnotationBeanPostProcessor 构造「stringRedisTemplate 与
signKeyStringRedisTemplate 共存」的最小上下文(复刻 appauth 在场的现场)
- 断言装配成功;断言绑定的是主库模板而非密钥专用模板
- 反向断言:裸 @Autowired 在双 bean 下必然抛 UnsatisfiedDependencyException
—— 钉死本次事故的成因,防止回退
既有测试为何漏掉:application-test.yml 的 redis-broadcast-enabled=false 把该 bean
整个关掉,装配分支从未被覆盖。
mvn -o test: 104/104 通过(新增 3 例)。
|
2026-09-24 10:57:42 +08:00 |
|
chenxing
|
f456c85702
|
feat(gateway): 入口分流 + ANON 豁免接线,退役 admin.html 治理小页
build / build-push (push) Successful in 1m10s
判定接线(SignVerifyFilter 拆三段,内部入口逻辑逐字节不变):
- 内部入口(容器网直连,无标记)一律验签,不看 visibility/authMode
- 外部入口(来源可信 + X-Entry: external)→ INTERNAL 裸 403;EXTERNAL×SIGNED 验签;
EXTERNAL×ANON 限流内免签放行(verdict=ANON / caller=anonymous / 不注入身份头),
超限 429、限流未就绪 403(fail-closed)
- 外部入口的 403/429 属策略层拒绝,与 observe 正交
新增:
- auth/EntryDetector:可信来源 CIDR + X-Entry 双条件判定,仅认 IPv4,非法一律不可信
- auth/AnonRateLimiter:ALLOW/EXCEEDED/UNAVAILABLE 契约
- auth/UnavailableAnonRateLimiter:T3.1 前的占位实现,恒 fail-closed
- route/RouteChangeBroadcaster:频道 gw:route:version 变更广播(判定仍读本地 Caffeine,
Redis 只做变更通知,Redis 异常回落本地快照,不存在“挂了就放行”)
其他:
- GatewayProperties 新增 trusted-proxies / anon-per-ip-qps
- StreamingForwarder 把 x-entry 加入剥除集(伪造值也到不了提供方)
- InternalAdminController 白名单 {SIGNED,ANON}、删 page()、写后广播;RouteRefreshController 广播
- 硬删 static/admin.html(治理面已前端化,重载注册表由 front 头部按钮承接)
- 测试:EntryDetectorTest、SignVerifyFilterEntryTest(入口×策略矩阵)等,101/101 全绿
|
2026-09-24 10:30:14 +08:00 |
|
chenxing
|
a19ded48ef
|
feat(ctx): SanitizeFilter 剥 context-path,业务路径空间与 ctx 解耦(ctx 为空零行为变化)
build / build-push (push) Successful in 47s
|
2026-09-23 16:50:34 +08:00 |
|
chenxing
|
2389d2fa9a
|
feat(admin): 管理面信封化+分页化,OpenAPI 文档端点旁路(B1-B6)
build / build-push (push) Successful in 1m59s
- pom: 引 yh-platform-dependencies(import) / yh-api-std / springdoc-openapi-ui 1.7.0 + nexus-public 仓库
- RoutingFilter.isGatewayInternal: /v3/api-docs、/swagger-ui/**、/swagger-ui.html 纳入自身路径旁路,避免被 TargetRouter 当 target 裸 404
- InternalAdminController: page/routes/targets/logs 三接口分页化返回 BasePageResult;补 @Operation(operationId=GatewayAdmin.*);错误契约去 @ResponseStatus(400) 改 200+code=2;logs 兼容旧 limit 入参
- RouteRefreshController: 补 @Tag/@Operation(operationId=GatewayAdmin.refresh)
- static/admin.html: 适配 {code,msg,data} 信封与 content/total 分页
- InternalAdminControllerTest: 重写 12 用例,77 项测试全绿
|
2026-09-23 12:17:02 +08:00 |
|
chenxing
|
6e64acc0c7
|
fix(config): 本地兜底端口 10010→10013,更正陈旧注释(B3,v1.2 §8-L5 收编)
build / build-push (push) Successful in 46s
|
2026-09-23 11:42:42 +08:00 |
|
chenxing
|
3887892d4d
|
feat(ops): 对齐平台日志策略——新增 logback-spring.xml(app.log 按天滚动/30天/5GB,root INFO)
build / build-push (push) Successful in 46s
此前无自定义 logback,走 Spring Boot 默认文件日志(spring.log 10MB 大小滚动、
仅留 7 天);现与 Notice/UserBase 一致:/app/logs/app.log 按天滚动。
日志级别由平台配置层管理(application-platform.yml root=INFO);私有配置中的
logging.level.root=DEBUG/show-sql 调试遗留已同步清除。
|
2026-09-23 09:46:53 +08:00 |
|
chenxing
|
ce4c3cc5a6
|
feat(admin): 治理小页完整前端——路由/目标行内编辑+台账查询
build / build-push (push) Successful in 51s
单文件 vanilla JS 零外部依赖:路由表六旋钮下拉/数字输入+行保存(值域即下拉白名单),
目标表 base_url+启停,台账三筛选+status 着色,顶部注册表热重载;错误 toast 不打断。
|
2026-09-23 00:13:43 +08:00 |
|
chenxing
|
06b0f4ed23
|
feat(admin): 网关治理小页后端——路由/目标/台账查询与行内编辑
/api/internal/admin/**(RoutingFilter 旁路前缀,零过滤器改动):
- GET page(routes/targets/logs) + PUT routes/{id} / targets/{id}
- 值域白名单(visibility/authMode/cacheScope)非法 400 不落库;写后热重载注册表
- OpenApiLogRepository.pageLatest 两可空过滤+倒序分页
- 10 用例(page/列表/合法编辑/三态 400/limit 截断),全量 75/75 绿
|
2026-09-23 00:12:17 +08:00 |
|
chenxing
|
50f9948b49
|
E11: open_api_target 表与 DB>yml 地址解析
build / build-push (push) Successful in 1m39s
target base-url 由 open_api_target 快照优先解析,无行/禁用行/空白地址行回落
yml yh.gateway.routes;/api/internal/routes/refresh 同时重载两表。
|
2026-09-22 10:14:46 +08:00 |
|
chenxing
|
1d354face9
|
E04a: /actuator/** 纳入网关自身端点旁路(探活不被 oapi 链裸 404)
build / build-push (push) Successful in 1m6s
projman 探活口径 = {ctx}/actuator/health 且只认 HTTP 200;网关原先只旁路
/api/internal/**,健康探针被 TargetRouter 判未知 target 裸 404 → HealthGuard
连续失败会周期性 restart,E05/E06 的 health=200 验收也不可能达成。
台账/验签/转发四处共用同一判定,故一处改动即全链生效。
|
2026-09-22 09:25:07 +08:00 |
|
chenxing
|
0545de48a8
|
E02: 注册表初版 cms 行修正为 yschcms(对齐 160 实测 ctx)
build / build-push (push) Successful in 1m37s
|
2026-09-22 09:08:22 +08:00 |
|
chenxing
|
3d50bac106
|
fix: 去掉 pom finalName=app(jar 已命名 app.jar 致 CI 'cp *.jar app.jar' 同文件拷贝失败;对齐平台约定:maven 产 artifactId-version.jar,由 CI 拷成 app.jar)
build / build-push (push) Successful in 55s
|
2026-09-21 10:53:16 +08:00 |
|
chenxing
|
4de8eda227
|
merge: 合并 projman 初始化的远端仓库(CI 文件以远端为准:.gitea/workflows + docker/Dockerfile;README 保留项目文档)
build / build-push (push) Failing after 16s
|
2026-09-21 10:47:16 +08:00 |
|
chenxing
|
10374abd6d
|
T1.6: 观察模式开关 + Filter 链组装(链序定型 台账0→Sanitize1→Routing2→SignVerify3→身份注入4(转发器内)→Dispatch5;/api/internal/** 三环旁路直达 controller;observe=true 坏签名放行、false 裸401 集成对照;400/404 协议层错误不受 observe 影响;关掉 starter AppAuthFilter(正确键 yh.app-auth.enabled=false)避免抢链首误 401)
|
2026-09-21 09:45:52 +08:00 |
|
chenxing
|
28b9bfca3c
|
T1.5: 台账异步落库(ArrayBlockingQueue(10000) offer 不阻塞;满200/500ms 单线程批量 saveAll+按日 upsert;队满原子计数+ERROR 不抛;关停 flush 余量;hibernate batch_size=200)
|
2026-09-21 09:29:48 +08:00 |
|
chenxing
|
26f5787000
|
T1.4: 身份头注入 X-Caller-App-Key(verdict=PASS 才注入验签 appKey;注入点在伪造头剥除之后,FAIL/ANON 不注入;四用例绿)
|
2026-09-21 09:25:13 +08:00 |
|
chenxing
|
cdc4396ec2
|
T1.3: StreamingForwarder 流式转发(AsyncContext+HttpClient 零缓冲透传;剥 hop-by-hop 与伪造 X-Caller-App-Key、签名头四件原样;超限裸413/连接失败裸502/超时裸504)
|
2026-09-21 09:22:07 +08:00 |
|
chenxing
|
58a1bb5358
|
T1.2: SignVerifyFilter v1(canonical 剥 target 首段+解码排序 query,复用 starter SignUtil ±5min;observe 只记不拦/非 observe 裸 401;共享向量为 starter 真实代码执行产出 v1.json 逐字节对拍)
|
2026-09-21 09:13:18 +08:00 |
|
chenxing
|
949296eb67
|
T1.1: SanitizeFilter 请求规整化(解码检查 ..///控制字符裸 400,只拒不修;attribute 契约 sanitized.uri/stripped.path)
|
2026-09-21 00:34:11 +08:00 |
|
chenxing
|
a45a180008
|
T0.13: 全平台 oapi 盘点产出注册表初版 02_init_routes.sql(22 条前缀聚合,全最保守形态)
|
2026-09-21 00:32:36 +08:00 |
|
chenxing
|
4777d47499
|
T0.12: GatewayProperties 路由表 + TargetRouter(/{target}/oapi/** 路由判定与 forwardUrl 换主机不换路径计算)
|
2026-09-21 00:25:54 +08:00 |
|
chenxing
|
6cb0fa1b5b
|
T0.11: GatewayKeyService 薄封装复用 starter SignKeyResolver(四态 fail-closed);显式引 data-redis(starter 标 optional 不传递)
|
2026-09-21 00:24:02 +08:00 |
|
chenxing
|
d4bfe8a3b4
|
T0.10: RouteRegistry Caffeine 装载/判定(精确优先+/**通配+最严默认)与 /api/internal/routes/refresh
|
2026-09-21 00:21:28 +08:00 |
|
chenxing
|
06a02750b0
|
T0.9: 注册表三表 DDL(01_schema.sql) + JPA 实体/Repository + H2 MODE=MySQL round-trip 与唯一约束测试
|
2026-09-21 00:20:01 +08:00 |
|
chenxing
|
f10343a4c1
|
T0.8: open-gateway 建仓——Spring Boot 2.7.18/JDK8 骨架 + EnvelopeWriter(裸码/信封两形态,信封与 SDK OpenApiEnvelope 字段对齐)+ CI/Dockerfile/.dockerignore
|
2026-09-21 00:17:49 +08:00 |
|