3 Commits
Author SHA1 Message Date
sun f7c7e6ee3a docs: v0.3.0 阶段三 文档、示例配置与发布说明
Docker Publish / build-and-push (push) Canceled after 0s
CI / build-and-test (push) Canceled after 0s
文档与配置同步 v0.3.0 的破坏性变更:

README.md:
- 特性列表更新:管理入口 /dashboard、凭证分离、默认无匿名监控端点
- 环境变量表补充 METRICS_ALLOW_CIDR,并说明未配任何管理凭证时服务拒绝启动
- 端点文档重写:/healthz(匿名且不含字段)、/health(需鉴权)、
  /metrics(默认 404,两种使用方式)、管理页面与安装页对照表
  (含"页面需鉴权为何又能直接打开"的内容协商说明)
- 公网部署安全清单重写:按端点列出真实暴露面,并提醒探针必须指向 /healthz
- 故障排查、架构表、迁移表中的 /admin 引用统一改为 /dashboard

.env.example:新增 METRICS_ALLOW_CIDR 与 admin_key 说明(含 Docker 网段警告)。

两处部署陷阱修复(阶段一给 /health 加鉴权引发的连带问题):
- docker-compose.yml 的 healthcheck 原指向 /health,加鉴权后会一律 401,
  导致容器被判定为 unhealthy → 改为 /healthz
- Dockerfile 的 HEALTHCHECK 同样指向 /health → 改为 /healthz
  (这两处若不改,升级后容器健康状态会持续异常,且现象与鉴权改动看起来无关,排查成本高)

新增 docs/RELEASE_NOTES_v0.3.0.md:可直接用于创建 Release,
含 Breaking Change 清单、新特性、验证方式与实测结果、升级步骤。

docs/IMPLEMENT_v0.3.0.md:
- 按合并后的阶段编号重写实施进度表与阶段标题
  (原「阶段 1 收紧鉴权」与「阶段 2 收口端点」合并为「阶段 1」,后续顺延),
  并说明合并原因:两者只做前者是"有风险无收益"
- 记录本轮实际验证结果

验证:go build / go vet / go test ./... -count=1 全绿。
2026-10-04 01:17:43 +08:00
sun 7b8f557f54 feat(router): v0.3.0 阶段二 管理入口迁移与前端同步
管理入口从 /admin 迁至 /dashboard:
- /dashboard、/dashboard/voices、/dashboard/settings 为新入口
- 原挂在 /dashboard 上的服务状态预览页(health.html)迁至 /dashboard/status,
  侧边栏新增「观测 → 详细状态」入口
- /admin 及子路径 301 永久重定向到对应新路径(页面用 301 是正确的)
- 静态资源同时注册 /dashboard/ 与 /admin/ 两套路径,
  避免过渡期出现"页面能开但丢样式"

前端同步:
- admin-shell.js:侧边栏导航、登出、登录跳转改指 /dashboard/*
- admin.html / admin-login.html / admin-voices.html / admin-settings.html:
  静态资源引用与登录跳转改指 /dashboard/*
- health.html:改用 admin-shell 的 http 实例并改调 /admin/health、/admin/metrics
  (该实例自动附加 Authorization: Bearer;原实现用裸 axios,不带凭证),
  并加登录校验与「返回控制台」入口
- setup.html:安装完成跳转目标改为 /dashboard,页面内 /admin 文案同步更新
- 各页面的 API 调用路径无需修改:axios baseURL 为 /api,
  故 /voices、/admin/overview 等自动落成 /api/admin/*

controller/setup.go:安装成功响应的 redirect 字段由 /admin 改为 /dashboard。

验证:go build / go vet / go test ./... -count=1 全绿;
另用真实服务器端到端验证:旧入口 301 全部正确、静态资源新旧路径均 200、
管理页面内容协商(html 200 / 非 html 401)、登录页公开、
各页面引用的静态资源均为新路径且无残留旧路径。
2026-10-04 01:17:26 +08:00
sun c18cf63518 feat(auth)!: v0.3.0 阶段一 鉴权收紧 + 健康/指标端点收口
本提交由初版方案的「阶段 1」与「阶段 2」合并而成。合并原因:两者是同一件事的两半——
只收紧鉴权而不收口端点,结果是"有风险无收益"(未配凭证的旧部署可能起不来,
而 /health、/dashboard、/metrics 仍匿名可读)。

一、鉴权收紧(原阶段 1)
- RequireAdmin 在凭证列表为空时不再放行。此前 len(keys)==0 直接 next.ServeHTTP,
  导致未配凭证的部署上管理接口完全裸奔,也让后续给端点加鉴权的加固形同虚设。
  现在该情况返回 401 并记录明确日志。
- 新增可选独立管理凭证 admin_key,取值优先级:
  admin_key(DB) > auth_key(DB) > OPENAI_TTS_API_KEY(env)。
  middleware.ValidateAPIKey(业务侧 /v1/audio/speech)保持只看 auth_key,
  于是配置 admin_key 后业务调用方持有的 key 无法访问管理接口,权限隔离成立;
  不配置则回退 auth_key,老部署行为不变。
  新增 PUT /api/admin/settings/admin-key 与旧前缀别名,
  凭证只写不读(GET 仅返回打码值与 admin_key_set / admin_key_source)。
- normal 模式下管理凭证为空时启动期 fail-fast。RequireAdmin 改为拒绝后,
  若此处不拦,服务会正常起来但 /dashboard 与全部 /api/admin/* 都是 401,
  等于把自己锁在门外;宁可启动失败并打印明确原因。

二、端点收口(原阶段 2)
- /health 改为鉴权(原匿名泄漏版本、commit、运行时长、内存、goroutine、配置错误文本)
- /dashboard 改为鉴权,并对浏览器 HTML 请求做内容协商(Accept 含 text/html 时
  返回页面外壳,由前端据 sessionStorage 显示登录视图;非 HTML 请求无凭证一律 401)。
  不做无条件 401 的原因:SPA 登录态存在 sessionStorage、不随请求发送,
  服务端无从判断是否已登录,强行 401 会把"打开看到登录页"变成"打开直接报错"。
  页面外壳不含任何数据,数据全部来自鉴权后的 API。
- /api/setup/status 改为鉴权(原本 normal 模式下仍匿名返回 installed/mode)
- 根路径 /metrics 默认完全不注册(访问 404);配置 METRICS_ALLOW_CIDR 后按内网
  白名单开放,非白名单返回 404 而非 403,不向扫描者确认端点存在。
- 新增 GET /healthz 匿名存活探针,只回 200 与字面量 ok、不含任何字段,解决
  "给 /health 加鉴权后 K8s 探针与 Docker HEALTHCHECK 会一律 401 导致 Pod 反复重启";
  新增 GET /api/admin/health 鉴权版详细健康数据。

IP 白名单中间件复用 GetClientIP(已处理 XFF 与 TRUSTED_PROXY_HOPS);
main.go 启动日志同步改为指向 /healthz 与 /api/admin/health。

BREAKING CHANGE:
1. /health、/dashboard、/api/setup/status 不再匿名可读;根路径 /metrics 需配
   METRICS_ALLOW_CIDR,否则 404。
2. 未配置 auth_key / admin_key / OPENAI_TTS_API_KEY 任一时,normal 模式下服务拒绝启动。
3. K8s 探针与 Docker HEALTHCHECK 必须改指 /healthz;Prometheus 请改用鉴权版
   /api/admin/metrics 或配置 METRICS_ALLOW_CIDR(Docker 中勿填 127.0.0.1/32,
   那是容器自身回环,应填容器内网网段)。

验证:go build / go vet / go test ./... -count=1 全绿(7 个包);
另用真实服务器端到端验证端点矩阵、内容协商、凭证隔离与 CIDR 白名单两种形态。
2026-10-04 01:17:06 +08:00
+5 -9
View File
@@ -2,17 +2,13 @@
本项目的所有重要变更都记录在本文档。版本号遵循 [SemVer](https://semver.org/)。 本项目的所有重要变更都记录在本文档。版本号遵循 [SemVer](https://semver.org/)。
## [0.2.4] - 2026-10-04 ## [未发布]
### 路由鉴权架构升级 · 健康/指标端点收口 · 管理入口迁移 ### v0.3.0 · 进行中
> ⚠️ **本版本为破坏性变更版本**,升级前请阅读 [Release Notes](docs/RELEASE_NOTES_v0.3.0.md)。 按 [docs/IMPLEMENT_v0.3.0.md](docs/IMPLEMENT_v0.3.0.md) 分阶段实施,当前完成 **阶段 1、2、3**。
>
> **版本号说明**:本次以 `0.2.4` 发布(按补丁号连续),但**语义上是破坏性变更** —— > **编号说明**:初版方案的"阶段 1(收紧鉴权)"与"阶段 2(收口端点)"属于同一次安全改造、
> 未配凭证的部署会拒绝启动、匿名监控端点被收口、探针需改指 `/healthz`。
> 之所以不用 minor 号,是为了保持编号连续;后续 `0.2.x` 用于修复本版本暴露的问题。
>
> **阶段编号说明**:初版方案的"阶段 1(收紧鉴权)"与"阶段 2(收口端点)"属于同一次安全改造、
> 必须一起上线才有意义(只做前者是"有风险无收益"),故已**合并为现在的「阶段 1」**; > 必须一起上线才有意义(只做前者是"有风险无收益"),故已**合并为现在的「阶段 1」**;
> 后续阶段依次顺延。下文的「阶段 N」均指合并后的编号。 > 后续阶段依次顺延。下文的「阶段 N」均指合并后的编号。