security: external API - only ID+Secret auth, remove legacy key & JWT

- removed x-external-key (single key) auth path + getExternalKey
- removed JWT passthrough in clientAuth (Bearer no longer accepted)
- removed /auth/login (JWT endpoint) and /my-tickets (JWT-only)
- clientAuth now mandatory: missing/invalid/disabled client -> 401
  (closed the 'no config = allow all' authorization bypass)
- moved /auth/register BEHIND clientAuth (was anonymous abuse surface)
- clients mgmt endpoints keep authenticate + role check (admin UI)
- docs + UI copy updated to single auth method
- verified: 30 checks incl. full-tree scan for legacy key refs
This commit is contained in:
2026-08-19 19:44:34 +08:00
parent 4dfc30ce89
commit 6056153f57
4 changed files with 29 additions and 88 deletions

View File

@@ -331,10 +331,7 @@ Base URL: `http://<host>:3100/api`
| 端点 | 认证 | 说明 |
|------|------|------|
| POST /external/auth/register | | 插件注册(邮箱验证链接) |
| POST /external/auth/login | — | 插件登录,返回 JWT |
| GET /external/my-tickets | Bearer | 我的工单列表(limit ≤50) |
| GET /external/my-tickets/:id | Bearer | 我的工单详情 |
| POST /external/auth/register | client | 插件注册(需客户端凭据;邮箱验证链接) |
| POST /external/tickets | client | 提交工单(带 `server` 可选;返回 id + tracking_token) |
| GET /external/tickets/track?token= | client | 按追踪码查工单状态+回复(提交→处理→结束全流程) |
| GET /external/all-tickets | client | 全部工单(分页 page/limit ≤200,可按 `server`/`status`/`type` 过滤) |
@@ -349,13 +346,11 @@ Base URL: `http://<host>:3100/api`
| PUT /external/clients/:id | Bearer(owner/admin) | 启用/停用客户端 |
| DELETE /external/clients/:id | Bearer(owner/admin) | 删除客户端 |
### 外部鉴权(三选一)
### 外部鉴权(唯一方式)
| 方式 | 请求头 | 适用 |
| 方式 | 请求头 | 说明 |
|------|--------|------|
| 多客户端(推荐) | `x-api-client-id` + `x-api-secret` | QQ机器人等外部系统,后台可创建/停用多个客户端 |
| 旧版单 key | `x-external-key` | 兼容旧部署(`config.external_api_key`) |
| 用户 JWT | `Authorization: Bearer <jwt>` | 插件/已登录用户 |
| ID + Secret(唯一) | `x-api-client-id` + `x-api-secret` | 后台可创建/停用多个客户端;无凭据或凭据错误一律 401 |
### 子服务器定位(`server` 参数)

View File

@@ -8,9 +8,7 @@
---
## 一、鉴权(三种方式,任选其一)
### 方式 A:ID + Secret(推荐,多客户端)
## 一、鉴权(唯一方式:ID + Secret)
在站点后台 →「外部API」页面创建客户端,获得一对凭据:
@@ -20,6 +18,7 @@ Secret: s_9f8e7d6c5b4a39281726354a1b2c3d4e5f60718293a4b5c6d7e8f9a0b1c2d3e
```
> ⚠️ Secret 只在创建时显示一次,请立即保存。支持创建多个客户端、单独停用/删除,互不影响。
> 无凭据 / 凭据错误 / 客户端停用 → 一律返回 `401`。
调用时在请求头携带:
@@ -28,18 +27,6 @@ Secret: s_9f8e7d6c5b4a39281726354a1b2c3d4e5f60718293a4b5c6d7e8f9a0b1c2d3e
| `x-api-client-id` | 你的 Client ID |
| `x-api-secret` | 你的 Secret |
### 方式 B:旧版单 Key(兼容)
| 请求头 | 值 |
|--------|-----|
| `x-external-key` | 部署时配置的 external_api_key |
### 方式 C:用户 JWT(仅限插件)
| 请求头 | 值 |
|--------|-----|
| `Authorization` | `Bearer <JWT>`(来自 `POST /api/external/auth/login`) |
---
## 二、快速开始(Python / Node 示例)
@@ -324,9 +311,10 @@ GET /api/external/stats?server=
## 六、鉴权失败排查
1. **401 未授权**:检查 `x-api-client-id` / `x-api-secret` 是否与创建时一致;客户端是否被停用;secret 是否完整无换行空格
2. **客户端被停用**:后台「外部API」→ 启用。
3. **需要多个客户端**:后台可创建多个,分别用于机器人 / 插件 / 统计面板,互不影响;删除即立即失效
1. **401 缺少凭据**:请求必须携带 `x-api-client-id` `x-api-secret` 两个请求头
2. **401 客户端鉴权失败**:检查 Client ID / Secret 是否与创建时一致;secret 是否完整无换行空格;客户端是否被停用。
3. **客户端被停用**:后台「外部API」→ 启用
4. **需要多个客户端**:后台可创建多个,分别用于机器人 / 插件 / 统计面板,互不影响;删除即立即失效。
---