English · 中文
注重安全、隐私的快速、轻量化 API 文档展示服务。
Caution
适用性 —— 务必先读。 api_show 面向 高保密性、权限粒度较粗 的场景:
- ✅ 适合: 仅在内网 / 局域网暴露的 API 文档;权限按 项目 + tag 前缀 粒度控制(例:「Alice 可见
payments项目的auth*/users*标签」)。 - ❌ 不适合: SaaS 多租户文档门户、按端点 / 按字段的细粒度 ACL、按操作限流、合规审计日志,或任何需要直接暴露在公网的部署。
如果需要操作级细粒度权限、审计追踪、SSO/OAuth 联邦登录、公网托管 —— 请选别的工具。api_show 用功能广度换来更小、更可审计的攻击面,目标只有一个:内网。
api_show 把多个生产者仓库的 OpenAPI 文档聚合成单一门户,由内嵌的 Redoc 渲染(本地静态资源,无 CDN 依赖)。各生产者仓库在 tag 发版时把自己的 docs/openapi.yaml POST 到门户;用户打开同一个 URL,从下拉菜单里选项目 + 版本,就能看到渲染后的接口文档。文档更新不需要重新编译门户。
| 登录 | 绑定 TOTP(首次) |
|---|---|
![]() |
![]() |
门户 — demo_a |
门户 — demo_b |
|---|---|
![]() |
![]() |
绑定页中的二维码与 base32 secret 已主动模糊 / 遮罩 —— 每个用户首次登录都会生成全新的 secret。
暗色主题色板与 Redoc 左侧栏 + 右侧代码面板对齐。Schema 标签 / 表格行通过 webroot/style.css 在 #api-reference 作用域内提升对比度。
威胁模型 —— 仅限局域网。 不暴露公网 IP,永远不上互联网。
only_local = true(默认)下,任何非私网 / 非环回 IP 命中/upload都会在应用层直接拒绝,不管 Bearer 是否正确。认证 —— 三种模式,由 TOML 中
auth_mode字段切换:
模式 行为 pwd仅用户名 + 密码。无 TOTP。适合 IDE 断点调试。 pwd_totp默认。先校验密码;若用户已绑定 TOTP,要求 6 位 2FA 码;否则直接发会话。 totp无密码。TOTP 即凭证;首次登录通过 /bind-totp自动绑定。TOML 中永不存密码。 Argon2id 哈希存放在
<data_dir>/pwd_blobs/下经 AES-GCM 加密的 sidecar blob。管理 CLI 可以创建用户而不需要知道明文密码 —— 见下文 添加用户。
api_show 的定位很窄:多份 OpenAPI 规范聚合到一个内网门户、按用户重写规范、不依赖 SaaS、单二进制部署。 同类工具大多缺其中一项,或者是完整的 SaaS 平台。
图例:✅ 支持 ·
| 能力 | api_show | Swagger UI / Redoc 原生 | Redocly CLI | Stoplight Elements | Stoplight Platform / Bump.sh | ReadMe.com | Mintlify | Backstage TechDocs |
|---|---|---|---|---|---|---|---|---|
| 单门户聚合 多份 OpenAPI 规范 | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ||
| 自托管单二进制,无运行时依赖 | ✅ | ✅ | ❌(SaaS) | ❌(SaaS) | ❌(SaaS) | ❌(重型平台) | ||
| 应用层强制 LAN-only(拒非 private/loopback IP) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | |
| 内置 多用户认证(密码 / TOTP / 2FA) | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | |
| 按用户 ACL:项目 + tag 前缀粒度 | ✅ | ❌ | ❌ | ❌ | ❌ | |||
| 服务端 重写规范,剔除未授权 op 后再下发 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| 生产者 上传端点(CI 在打 tag 时 POST 规范) | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | |
| 运行时 无 CDN / 无外网字体抓取 | ✅ | ❌ | ❌ | ❌ | ||||
| 密码 永不入配置,argon2id PHC 存于 AES-GCM blob | ✅ | — | — | — | ✅ | ✅ | ✅ | |
管理员 CLI 永不见明文密码(走 /set-password 流) |
✅ | — | — | — | ||||
| 规范更新 无需重编 / 重部署 门户 | ✅ | ❌(需重编) | ✅ | ✅ | ❌(需重编) | ❌(需重编) | ||
| 审计日志 / SSO / 单接口级 ACL | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | |
| 支持 公网托管 部署 | ❌(刻意) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
选 api_show 当且仅当 同时满足:
- 多个内部团队各自维护 OpenAPI 规范,需要单门户列出全部。
- 访问范围在 LAN / VPN 内;不愿依赖 SaaS、不愿把文档暴露到公网。
- 粗粒度访问控制(每用户 项目 + tag 前缀)够用;不需要单接口 / 单字段 ACL 或审计追溯。
- 想要一个单 Go 二进制 + 内嵌 Redoc:无 Node 工具链、无构建流水线、运行时不打 CDN。
选别的工具当 你需要其中任一:单接口 ACL、审计日志、SSO / OIDC 联合登录、公网托管、细粒度配额 / 限流,或是带营销页的精致文档 CMS。
# 1. 下载 release 包
wget https://github.com/0xYeah/api_show/releases/download/<VERSION>/api_show_linux_release_<VERSION>.zip
unzip api_show_linux_release_<VERSION>.zip && cd api_show
# 2. 一键安装(创建 /api_show/{api_show, conf/, logs/},安装 systemd unit)
sudo ./install_api_show.sh
# 3. 启动 → 编辑配置 → 重启
sudo systemctl start api_show
sudo $EDITOR /api_show/conf/api_show_config.toml # 填 secret + upload_token
sudo systemctl restart api_show
sudo systemctl status api_showinstall_api_show.sh 行为:
| 动作 | 说明 |
|---|---|
install(默认) |
首次安装。已存在的二进制 + 配置会加 _YYYY-MM-DD_HH-MM-SS 备份后缀。 |
update |
停服务 → 替换二进制(保留 data/ + conf/)→ 重启。 |
uninstall |
停服务 + 删 unit 文件 + 删 /api_show/ 目录(不可恢复)。 |
路径:/api_show/conf/api_show_config.toml(首次启动时自动用占位值生成)。
# HMAC cookie 密钥 + 单 blob 密钥派生 salt。≥ 16 字节,ASCII。
secret = "REPLACE_ME_at_least_16_chars"
# /upload 接受的 Bearer token。
upload_token = "REPLACE_ME_bearer_token"
# 上传 spec + totp_blobs/ + pwd_blobs/ 的根目录。
data_dir = "./data"
# HTTP 监听端口。仅绑 IPv4 0.0.0.0。
port = 12110
# 内网模式。true = /upload 在应用层拒绝任何非私网 / 非环回 IP,
# 与 Bearer 是否正确无关。
only_local = true
# 认证策略:pwd | pwd_totp(默认)| totp
auth_mode = "pwd_totp"
# 用户名册 + 单用户 ACL。改完重启即生效。
# TOML 永不存密码 —— 密码以加密 blob 存放在 <data_dir>/pwd_blobs/。
# 详见「添加用户」。
[[users]]
username = "alice"
acl = { demo_a = ["*"], demo_b = ["auth", "users"] }
[[users]]
username = "bob"
acl = { demo_a = ["*"] }约束:
secret为空或不足 16 字节 → 进程拒绝启动。upload_token为空 →/upload返回503 uploads disabled。auth_mode不在{pwd, pwd_totp, totp}范围 → 进程拒绝启动。- 不读取任何环境变量。配置只来自 TOML;改部署 = 覆盖文件。
- 首次启动若文件不存在,会写入占位配置 —— 启动永不会因「缺配置文件」而失败。
GET /login→ 输入username+ 密码 → 提交。- Argon2id 校验通过 → 发 7 天会话 cookie →
302跳/。
GET /login→ 输入username+ 密码 → 提交。- 密码通过 → 门户检查用户是否已绑 TOTP。
- 未绑 → 直接发会话 →
302跳/。 - 已绑 →
302跳/login-totp。
- 未绑 → 直接发会话 →
/login-totp→ 输入 6 位码 → 发会话 →302跳/。
GET /login→ 输入username,TOTP 留空 → 提交。- 账号未绑 →
302跳/bind-totp,扫二维码 + 输入首个码 → secret 加密落盘 → 发会话 →302跳/。 - 后续登录:
username+ 6 位码 → 校验 → 会话 →/。
如果用户是用 add_user 创建但没带 -p,或被 reset_pwd 重置过,下次登录时门户会重定向到 /set-password。用户自己挑密码(≥ 8 位);管理员永远看不到明文。
登录后,根页面用两个下拉菜单列出可见的项目 + 版本。当前选择会反映在 URL 上,方便分享给同一 ACL 的用户。
管理 CLI 永远不会输出明文密码。两种添加模式:
模式 1 —— 管理员设初始密码,用户后续自改:
sudo /api_show/api_show add_user alice -p "InitChangeMe!8" -acl "demo_a=*;demo_b=auth"
sudo systemctl restart api_show
# 把初始密码以带外渠道告诉 Alice(如签名邮件)。
# 任何时候管理员跑 `reset_pwd alice`,下次登录就走 /set-password 让 Alice 自己改。模式 2 —— 用户首次登录时自己挑密码:
sudo /api_show/api_show add_user alice -acl "demo_a=*"
sudo systemctl restart api_show
# 告诉 Alice 用任意密码访问 /login。
# 她会被重定向到 /set-password,自己挑一个。-acl 语法:proj1=tag1,tag2;proj2=*。* 表示该项目的所有 tag。不带 -acl 会写入空 ACL 块(管理员之后可以直接编辑 TOML 中的 [[users]])。
CLI 会向当前生效的配置文件追加一个 [[users]] 块(保留你的注释);带 -p 时还会写加密密码 blob。
./api_show version # 构建身份(commit / 时间 / OS / Go 版本)
./api_show add_user <user> [-p <plaintext>] # 追加 [[users]] 块 + 可选 pwd blob
[-acl <spec>]
./api_show reset_pwd <user> # 删 pwd blob;用户下次登录走 /set-password
./api_show reset_totp <user> # 删 TOTP blob;用户下次登录重新绑定(totp / pwd_totp 模式)生产者发版脚本只在 git push --tags 成功后才把 docs/openapi.yaml POST 到门户。endpoint + token 来自生产者仓库内一份 git-ignored 文件(不读环境变量):
# 在生产者仓库根目录
cat > .gen_docs.local <<'EOF'
DEPLOY_ADDR=http://<portal-host>:12110
DEPLOY_TOKEN=<必须与 api_show 的 upload_token 一致>
# ALLOW_LOOPBACK=1 # 仅本机自测时打开
EOF生产者各自维护自己的 gen_docs.sh(或同等脚本)。参考实现默认拒绝环回地址(127.0.0.1、localhost、[::1]、0.0.0.0),除非显式设置 ALLOW_LOOPBACK=1 走本地自测。
手动上传(本地自测):
curl -X POST \
-H "Authorization: Bearer <upload_token>" \
--data-binary @./docs/openapi.yaml \
"http://127.0.0.1:12110/upload?project=<proj_id>&version=v0.0.1&latest=true"| 参数 | 含义 |
|---|---|
project |
项目 id(同时用作数据目录名 + ACL 键)。 |
version |
vX.Y.Z 形式。 |
latest |
true 把该版本标记为默认(在下拉菜单中默认选中)。 |
名册 + 权限存在 TOML 的 [[users]] 中:
- 每个
acl映射:项目 id → 允许的 tag 前缀。 *= 该项目下所有 tag。- 用户
acl中没有的项目 = 该用户完全不可见。 GET /api/sources.json会过滤掉调用者无权访问的项目。GET /data/<proj>/<ver>/openapi.yaml会重写 spec,移除不允许的 operation + tag 声明。
改名册 = 改配置 + 重启。 编辑 /api_show/conf/api_show_config.toml(或用 add_user / reset_pwd),然后 systemctl restart api_show。无须打 tag / 发 release。
curl http://<portal-host>:12110/healthz # 200 OK = 存活sudo ./install_api_show.sh updateupdate 保留 /api_show/data/(spec + TOTP/pwd blob)和 /api_show/conf/;只替换二进制。
sudo ./install_api_show.sh uninstall停服务,删 unit 文件,递归删除 /api_show/(含数据 —— 不可恢复)。
- 设计上仅限内网部署。
only_local = true下,/upload拒绝外网 IP,与 token 无关。 - 监听绑定
0.0.0.0(IPv4)—— 没有 IPv6 双栈监听。 secret(≥ 16 字节)用于 HMAC 签名 cookie 以及 pwd / TOTP blob 的 AES-GCM 单用户密钥派生。- 密码:argon2id(m=64 MiB, t=3, p=2),PHC 格式输出,永不明文落盘 / 入 TOML。
- Cookie:HttpOnly + SameSite=Lax。前面套 nginx TLS 后把
Secure=true打开。 - 除
/upload外没有任何远程写 API;改用户名册必须有主机文件系统访问权限。
go build ./... # debug 二进制
./build.sh # 带版本戳的发版包go.mod 要求 Go 1.24+。依赖纯 Go。
见 LICENSE。



