734 lines
15 KiB
Markdown
734 lines
15 KiB
Markdown
# 管理接口契约(Admin API)
|
||
|
||
| 项 | 内容 |
|
||
|---|---|
|
||
| 版本 | 0.1(T0.4 契约) |
|
||
| 对应 | [DEVELOPMENT.md](../DEVELOPMENT.md) 第 8 节、[PRD.md](../PRD.md) F17 |
|
||
| 读者 | 后台接口 A、后台网页 W、集成测试 |
|
||
|
||
本文约定管理后台 HTTP 接口的方法、路径、请求字段、成功响应、分页与错误格式。W 线可先按本文用假数据开发;A 线实现时响应字段名与语义须与本文一致。
|
||
|
||
**硬性规则**
|
||
|
||
- 所有 JSON 响应在序列化前去掉消息正文;响应中不得出现 `body` 字段(含嵌套)。
|
||
- 管理接口不开跨域。
|
||
- 时间字段为 Unix 毫秒(整数),JSON 字段名蛇形。
|
||
|
||
---
|
||
|
||
## 1. 鉴权与通用约定
|
||
|
||
### 1.1 Cookie 会话(网页登录)
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| Cookie 名 | `nixmsg_admin` |
|
||
| 属性 | `HttpOnly`;`SameSite=Lax`;经 HTTPS(含受信任代理认定的 HTTPS)时加 `Secure` |
|
||
| 服务端 | 只存令牌哈希;默认有效 12 小时 |
|
||
|
||
改变状态的请求(POST / PATCH / PUT / DELETE)在使用 Cookie 鉴权时,必须带请求头:
|
||
|
||
```http
|
||
X-Nixmsg-Request: 1
|
||
```
|
||
|
||
缺少该头返回 **403**(防跨站表单)。`GET` 不要求此头。
|
||
|
||
### 1.2 API 令牌(程序调用)
|
||
|
||
```http
|
||
Authorization: Bearer nxm_...
|
||
```
|
||
|
||
- 带 Bearer 令牌时**不看** Cookie,也**不要求** `X-Nixmsg-Request`。
|
||
- 权限等同管理员,但不能调用:
|
||
- `POST /api/admin/password`
|
||
- `/api/admin/tokens` 及其子路径
|
||
- 令牌不过期;停用或删除后立即失效。
|
||
- 错误令牌按来源 IP 计入管理员登录锁定。
|
||
|
||
### 1.3 通用响应信封
|
||
|
||
成功(业务成功):
|
||
|
||
```json
|
||
{"ok": true, "data": { }}
|
||
```
|
||
|
||
失败:
|
||
|
||
```json
|
||
{"ok": false, "error": {"code": "unauthorized", "message": "未登录"}}
|
||
```
|
||
|
||
| HTTP | 常见 code | 说明 |
|
||
|---|---|---|
|
||
| 400 | `bad_request` | 字段不合法 |
|
||
| 401 | `unauthorized` | 未登录、密码错误、令牌无效 |
|
||
| 403 | `forbidden` | 缺 `X-Nixmsg-Request`、令牌无权访问该路由、已锁定等 |
|
||
| 404 | `not_found` | 资源不存在 |
|
||
| 409 | `id_taken` / `conflict` | 编号占用等 |
|
||
| 429 | `rate_limited` | 登录/令牌试错锁定 |
|
||
| 500 | `internal` | 服务器错误 |
|
||
| 503 | `busy` | 暂时不可用,可重试 |
|
||
|
||
列表类成功时 `data` 形如:
|
||
|
||
```json
|
||
{
|
||
"items": [ ],
|
||
"next_cursor": "",
|
||
"total": 0
|
||
}
|
||
```
|
||
|
||
- `next_cursor` 为空表示没有下一页。
|
||
- `total` 为符合筛选条件的总数(可选实现;契约要求有该字段,假数据可给 `items.length`)。
|
||
- 默认 `limit` 为 50,最大 200(除非单接口另有说明)。
|
||
|
||
### 1.4 操作日志
|
||
|
||
每个改变状态的请求写结构化日志:操作者(`admin` 或 `token:<名称>`)、动作、对象编号、结果、来源 IP。不写密码、令牌和正文。
|
||
|
||
---
|
||
|
||
## 2. 认证与账号
|
||
|
||
### 2.1 登录
|
||
|
||
`POST /api/admin/login`
|
||
|
||
不需要已登录。不要求 `X-Nixmsg-Request`。
|
||
|
||
请求:
|
||
|
||
```json
|
||
{"username": "admin", "password": "..."}
|
||
```
|
||
|
||
- `username` 固定为 `admin`。
|
||
- 成功时设置 Cookie `nixmsg_admin`。
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{"username": "admin"}
|
||
```
|
||
|
||
失败:密码错误 `401 unauthorized`;锁定 `429 rate_limited`。
|
||
|
||
### 2.2 登出
|
||
|
||
`POST /api/admin/logout`
|
||
|
||
作废当前会话 Cookie。成功 `data` 可为 `{}`。
|
||
|
||
### 2.3 当前管理员
|
||
|
||
`GET /api/admin/me`
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{"username": "admin", "auth": "cookie"}
|
||
```
|
||
|
||
`auth` 为 `cookie` 或 `token`(API 令牌访问时)。
|
||
|
||
### 2.4 修改管理员密码
|
||
|
||
`POST /api/admin/password`
|
||
|
||
**仅 Cookie 会话**;API 令牌调用返回 `403 forbidden`。
|
||
|
||
请求:
|
||
|
||
```json
|
||
{"old_password": "...", "new_password": "..."}
|
||
```
|
||
|
||
- 新密码至少 12 位。
|
||
- 成功后可选择保持当前会话或全部作废(实现默认:当前会话保留,其它会话作废)。成功 `data`:`{}`。
|
||
|
||
---
|
||
|
||
## 3. 概览
|
||
|
||
`GET /api/admin/overview`
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"version": "0.1.0",
|
||
"endpoints_total": 0,
|
||
"endpoints_online": 0,
|
||
"endpoints_disabled": 0,
|
||
"groups_total": 0,
|
||
"messages_pending": 0,
|
||
"messages_scheduled": 0,
|
||
"uptime_ms": 0
|
||
}
|
||
```
|
||
|
||
不含正文、不含端编号明细。
|
||
|
||
---
|
||
|
||
## 4. 端(endpoints)
|
||
|
||
### 4.1 列表
|
||
|
||
`GET /api/admin/endpoints`
|
||
|
||
查询参数:
|
||
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `cursor` | 分页游标 |
|
||
| `limit` | 默认 50,最大 200 |
|
||
| `source` | 可选:`admin` / `self` |
|
||
| `online` | 可选:`true` / `false` |
|
||
| `enabled` | 可选:`true` / `false` |
|
||
| `query` | 可选:编号前缀或名称包含,不区分大小写 |
|
||
|
||
成功 `data.items[]`:
|
||
|
||
```json
|
||
{
|
||
"id": "device-1",
|
||
"name": "门口",
|
||
"remark": "",
|
||
"source": "admin",
|
||
"enabled": true,
|
||
"online": false,
|
||
"online_since_ms": null,
|
||
"offline_since_ms": 1750000000000,
|
||
"talk_password_set": false,
|
||
"default_delay_ms": 0,
|
||
"created_at_ms": 1750000000000,
|
||
"login_locked": false
|
||
}
|
||
```
|
||
|
||
无密码、无正文。
|
||
|
||
### 4.2 开通
|
||
|
||
`POST /api/admin/endpoints`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"id": "",
|
||
"name": "门口",
|
||
"remark": "",
|
||
"login_password": "",
|
||
"talk_password": "",
|
||
"default_delay_seconds": 0
|
||
}
|
||
```
|
||
|
||
字段规则同 PRD F01(编号小写、密码不以 `nst_` 开头等)。`id` / `login_password` 留空则服务器生成。
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"id": "e_ab12cd34",
|
||
"login_password": "只在本次生成时返回"
|
||
}
|
||
```
|
||
|
||
冲突:`409 id_taken`。
|
||
|
||
### 4.3 批量开通(CSV)
|
||
|
||
`POST /api/admin/endpoints/import`
|
||
|
||
- `Content-Type: text/csv` 或 `multipart/form-data`(字段名 `file`)。
|
||
- UTF-8,可带 BOM。
|
||
- 表头:`id,name,login_password,talk_password,default_delay_seconds,remark`
|
||
- 最多 1000 行。先整体校验,任一行出错则一行都不建。
|
||
|
||
校验失败(HTTP 400):
|
||
|
||
```json
|
||
{
|
||
"ok": false,
|
||
"error": {"code": "bad_request", "message": "CSV 校验失败"},
|
||
"data": {
|
||
"errors": [{"line": 3, "reason": "编号不合法"}]
|
||
}
|
||
}
|
||
```
|
||
|
||
(实现可将 `errors` 放在 `error` 旁的 `data`;W 线按 `data.errors` 读取。)
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{"id": "e_1", "login_password": "生成或原文(仅此一次)", "name": "..."}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 4.4 多选批量
|
||
|
||
`POST /api/admin/endpoints/batch`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{"ids": ["a", "b"], "action": "disable"}
|
||
```
|
||
|
||
`action`:`disable` | `enable` | `delete`。
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{"ok_ids": ["a"], "failed": [{"id": "b", "code": "not_found"}]}
|
||
```
|
||
|
||
### 4.5 详情
|
||
|
||
`GET /api/admin/endpoints/{id}`
|
||
|
||
成功 `data` 同列表项,可额外含:
|
||
|
||
```json
|
||
{"session_issued_at_ms": null, "session_used_at_ms": null}
|
||
```
|
||
|
||
仍无密码哈希与正文。
|
||
|
||
### 4.6 修改
|
||
|
||
`PATCH /api/admin/endpoints/{id}`
|
||
|
||
请求(皆可选):
|
||
|
||
```json
|
||
{
|
||
"name": "新名",
|
||
"remark": "",
|
||
"default_delay_seconds": 0,
|
||
"enabled": true
|
||
}
|
||
```
|
||
|
||
成功 `data` 为更新后的详情(同 4.5)。
|
||
|
||
### 4.7 删除
|
||
|
||
`DELETE /api/admin/endpoints/{id}`
|
||
|
||
成功 `data`:`{}`。级联行为见 PRD F01 / DEVELOPMENT 7.6。
|
||
|
||
### 4.8 踢下线
|
||
|
||
`POST /api/admin/endpoints/{id}/kick`
|
||
|
||
只断开当前连接,不阻止令牌重连。成功 `data`:`{"kicked": true}`(当时不在线可为 `false`)。
|
||
|
||
### 4.9 重置登录密码
|
||
|
||
`POST /api/admin/endpoints/{id}/reset-login-password`
|
||
|
||
请求体可空 `{}`,或 `{"login_password": ""}`(留空则生成)。
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{"login_password": "只出现一次"}
|
||
```
|
||
|
||
会话令牌作废;在线连接收到 `fatal`(`password_reset`)后断开。
|
||
|
||
### 4.10 设置对话密码
|
||
|
||
`PUT /api/admin/endpoints/{id}/talk-password`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{"talk_password": ""}
|
||
```
|
||
|
||
空字符串表示清除。增加对话密码版本号,旧授权失效。成功 `data`:`{"talk_password_set": false}`。
|
||
|
||
### 4.11 解除登录锁定
|
||
|
||
`POST /api/admin/endpoints/{id}/unlock`
|
||
|
||
清除该编号的两种登录锁定。成功 `data`:`{}`。
|
||
|
||
---
|
||
|
||
## 5. 注册设置
|
||
|
||
### 5.1 获取
|
||
|
||
`GET /api/admin/registration`
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"enabled": false,
|
||
"code": "明文安全码(后台可查看)",
|
||
"updated_at_ms": 1750000000000
|
||
}
|
||
```
|
||
|
||
### 5.2 更新
|
||
|
||
`PUT /api/admin/registration`
|
||
|
||
请求(字段皆可选,至少一项):
|
||
|
||
```json
|
||
{"enabled": true, "code": "新码", "generate": false}
|
||
```
|
||
|
||
- `generate: true` 时服务器生成 16 位安全码并忽略请求里的 `code`。
|
||
- 成功 `data` 同 GET。
|
||
|
||
---
|
||
|
||
## 6. API 令牌
|
||
|
||
以下路由**仅 Cookie 会话**;Bearer 调用返回 `403 forbidden`。
|
||
|
||
### 6.1 列表
|
||
|
||
`GET /api/admin/tokens`
|
||
|
||
成功 `data.items[]`:
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"name": "ops",
|
||
"enabled": true,
|
||
"created_at_ms": 1750000000000,
|
||
"last_used_at_ms": null
|
||
}
|
||
```
|
||
|
||
不含令牌明文。
|
||
|
||
### 6.2 创建
|
||
|
||
`POST /api/admin/tokens`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{"name": "ops"}
|
||
```
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"name": "ops",
|
||
"token": "nxm_只出现一次",
|
||
"created_at_ms": 1750000000000
|
||
}
|
||
```
|
||
|
||
### 6.3 修改
|
||
|
||
`PATCH /api/admin/tokens/{id}`
|
||
|
||
请求(可选字段):
|
||
|
||
```json
|
||
{"name": "new", "enabled": false}
|
||
```
|
||
|
||
成功 `data` 同列表项。
|
||
|
||
### 6.4 删除
|
||
|
||
`DELETE /api/admin/tokens/{id}`
|
||
|
||
成功 `data`:`{}`。
|
||
|
||
---
|
||
|
||
## 7. 群(groups)
|
||
|
||
### 7.1 列表
|
||
|
||
`GET /api/admin/groups`
|
||
|
||
查询:`cursor`、`limit`、`query`(名称包含)。
|
||
|
||
成功 `data.items[]`:
|
||
|
||
```json
|
||
{
|
||
"id": "g_ab12cd34",
|
||
"name": "一组",
|
||
"owner_id": "a",
|
||
"member_count": 3,
|
||
"created_at_ms": 1750000000000
|
||
}
|
||
```
|
||
|
||
### 7.2 创建
|
||
|
||
`POST /api/admin/groups`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"id": "",
|
||
"name": "一组",
|
||
"owner_id": "a",
|
||
"member_ids": ["b", "c"]
|
||
}
|
||
```
|
||
|
||
后台**不要求**对话密码。`id` 留空则生成。部分成员失败时群仍创建,响应列出失败项。
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"id": "g_ab12cd34",
|
||
"name": "一组",
|
||
"owner_id": "a",
|
||
"failed": [{"id": "c", "code": "not_found"}]
|
||
}
|
||
```
|
||
|
||
### 7.3 改名
|
||
|
||
`PATCH /api/admin/groups/{id}`
|
||
|
||
请求:`{"name": "新名"}`。成功 `data` 为群摘要(同列表项)。
|
||
|
||
### 7.4 解散
|
||
|
||
`DELETE /api/admin/groups/{id}`
|
||
|
||
成功 `data`:`{}`。
|
||
|
||
### 7.5 加人
|
||
|
||
`POST /api/admin/groups/{id}/members`
|
||
|
||
请求:`{"member_ids": ["d"]}`。
|
||
|
||
成功 `data`:`{"failed": []}`(结构同创建时的 `failed`)。
|
||
|
||
### 7.6 移除成员
|
||
|
||
`DELETE /api/admin/groups/{id}/members/{endpointId}`
|
||
|
||
成功 `data`:`{}`。
|
||
|
||
### 7.7 转让群主
|
||
|
||
`POST /api/admin/groups/{id}/transfer`
|
||
|
||
请求:`{"endpoint_id": "b"}`。成功 `data`:`{"owner_id": "b"}`。
|
||
|
||
### 7.8 群详情(成员分页)
|
||
|
||
契约补充:`GET /api/admin/groups/{id}`(DEVELOPMENT 路由表未单列,但列表改名/解散需要详情;W 线可用)
|
||
|
||
查询:`cursor`、`limit`。
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"id": "g_ab12cd34",
|
||
"name": "一组",
|
||
"owner_id": "a",
|
||
"created_at_ms": 1750000000000,
|
||
"members": [
|
||
{"id": "a", "name": "", "online": true, "joined_at_ms": 1750000000000}
|
||
],
|
||
"next_cursor": ""
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 消息记录(messages)
|
||
|
||
响应**不得**含正文或 `body` 字段。
|
||
|
||
### 8.1 列表
|
||
|
||
`GET /api/admin/messages`
|
||
|
||
查询参数(PRD F17):
|
||
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `cursor` / `limit` | 分页 |
|
||
| `sender_id` | 发送方 |
|
||
| `endpoint_id` | 接收端(投递表) |
|
||
| `group_id` | 目标群 |
|
||
| `state` | 消息级状态:`scheduled` / `dispatched` / `completed` |
|
||
| `from_ms` / `to_ms` | 按 `created_at` 时间范围 |
|
||
|
||
成功 `data.items[]`:
|
||
|
||
```json
|
||
{
|
||
"seq": 1,
|
||
"id": "018f...",
|
||
"sender_id": "a",
|
||
"dest_kind": "endpoint",
|
||
"dest_id": "b",
|
||
"state": "completed",
|
||
"reason": "",
|
||
"send_at_ms": 1750000010000,
|
||
"created_at_ms": 1750000000000,
|
||
"keep": false,
|
||
"receipt": true,
|
||
"content_type": "text/plain",
|
||
"delivery_counts": {
|
||
"pending": 0,
|
||
"accepted": 1,
|
||
"recalled": 0,
|
||
"expired": 0,
|
||
"dropped": 0,
|
||
"rejected": 0
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.2 详情(各接收端)
|
||
|
||
`GET /api/admin/messages/{seq}`
|
||
|
||
成功 `data`:
|
||
|
||
```json
|
||
{
|
||
"seq": 1,
|
||
"id": "018f...",
|
||
"sender_id": "a",
|
||
"dest_kind": "group",
|
||
"dest_id": "g_1",
|
||
"state": "dispatched",
|
||
"reason": "",
|
||
"send_at_ms": 1750000010000,
|
||
"created_at_ms": 1750000000000,
|
||
"meta": {},
|
||
"content_type": "text/plain",
|
||
"deliveries": [
|
||
{
|
||
"endpoint_id": "b",
|
||
"state": "pending",
|
||
"reason": "",
|
||
"attempts": 1,
|
||
"pushed_at_ms": 1750000010100,
|
||
"updated_at_ms": 1750000010100
|
||
}
|
||
],
|
||
"next_cursor": ""
|
||
}
|
||
```
|
||
|
||
`deliveries` 可分页(`cursor` / `limit` 查询参数)。无正文。
|
||
|
||
---
|
||
|
||
## 9. 只读运行参数
|
||
|
||
`GET /api/admin/settings`
|
||
|
||
成功 `data`(只读,对应配置与生效值;不含密钥):
|
||
|
||
```json
|
||
{
|
||
"listen": ":7443",
|
||
"admin_listen": "",
|
||
"session_idle_days": 30,
|
||
"record_retention_days": 7,
|
||
"idempotency_hours": 24,
|
||
"receipt_retention_days": 7,
|
||
"sqlite_synchronous": "FULL",
|
||
"limits": {
|
||
"max_body_bytes": 262144,
|
||
"max_meta_bytes": 4096,
|
||
"max_frame_bytes": 786432,
|
||
"max_ttl_seconds": 2592000,
|
||
"max_schedule_seconds": 31536000,
|
||
"max_group_members": 1000,
|
||
"grace_seconds": 60,
|
||
"ack_timeout_seconds": 300,
|
||
"delivery_window": 32,
|
||
"receipt_window": 64,
|
||
"requests_per_second": 50,
|
||
"max_pending_per_sender": 10000,
|
||
"max_pending_per_receiver": 10000
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 路由速查
|
||
|
||
| 方法 | 路径 | Cookie 可变 | Bearer | 节 |
|
||
|---|---|---|---|---|
|
||
| POST | `/api/admin/login` | — | — | 2.1 |
|
||
| POST | `/api/admin/logout` | 要 | 可 | 2.2 |
|
||
| GET | `/api/admin/me` | — | 可 | 2.3 |
|
||
| POST | `/api/admin/password` | 要 | **否** | 2.4 |
|
||
| GET | `/api/admin/overview` | — | 可 | 3 |
|
||
| GET | `/api/admin/endpoints` | — | 可 | 4.1 |
|
||
| POST | `/api/admin/endpoints` | 要 | 可 | 4.2 |
|
||
| POST | `/api/admin/endpoints/import` | 要 | 可 | 4.3 |
|
||
| POST | `/api/admin/endpoints/batch` | 要 | 可 | 4.4 |
|
||
| GET | `/api/admin/endpoints/{id}` | — | 可 | 4.5 |
|
||
| PATCH | `/api/admin/endpoints/{id}` | 要 | 可 | 4.6 |
|
||
| DELETE | `/api/admin/endpoints/{id}` | 要 | 可 | 4.7 |
|
||
| POST | `/api/admin/endpoints/{id}/kick` | 要 | 可 | 4.8 |
|
||
| POST | `/api/admin/endpoints/{id}/reset-login-password` | 要 | 可 | 4.9 |
|
||
| PUT | `/api/admin/endpoints/{id}/talk-password` | 要 | 可 | 4.10 |
|
||
| POST | `/api/admin/endpoints/{id}/unlock` | 要 | 可 | 4.11 |
|
||
| GET | `/api/admin/registration` | — | 可 | 5.1 |
|
||
| PUT | `/api/admin/registration` | 要 | 可 | 5.2 |
|
||
| GET | `/api/admin/tokens` | — | **否** | 6.1 |
|
||
| POST | `/api/admin/tokens` | 要 | **否** | 6.2 |
|
||
| PATCH | `/api/admin/tokens/{id}` | 要 | **否** | 6.3 |
|
||
| DELETE | `/api/admin/tokens/{id}` | 要 | **否** | 6.4 |
|
||
| GET | `/api/admin/groups` | — | 可 | 7.1 |
|
||
| POST | `/api/admin/groups` | 要 | 可 | 7.2 |
|
||
| GET | `/api/admin/groups/{id}` | — | 可 | 7.8 |
|
||
| PATCH | `/api/admin/groups/{id}` | 要 | 可 | 7.3 |
|
||
| DELETE | `/api/admin/groups/{id}` | 要 | 可 | 7.4 |
|
||
| POST | `/api/admin/groups/{id}/members` | 要 | 可 | 7.5 |
|
||
| DELETE | `/api/admin/groups/{id}/members/{endpointId}` | 要 | 可 | 7.6 |
|
||
| POST | `/api/admin/groups/{id}/transfer` | 要 | 可 | 7.7 |
|
||
| GET | `/api/admin/messages` | — | 可 | 8.1 |
|
||
| GET | `/api/admin/messages/{seq}` | — | 可 | 8.2 |
|
||
| GET | `/api/admin/settings` | — | 可 | 9 |
|
||
|
||
「Cookie 可变」列:改变状态且走 Cookie 时必须带 `X-Nixmsg-Request: 1`。
|
||
|
||
---
|
||
|
||
## 11. 假数据开发提示(W 线)
|
||
|
||
- 可用静态 JSON 或 MSW;列表返回 2~3 条样例即可。
|
||
- 重置密码 / 创建令牌 / 开通生成密码的响应只展示一次,刷新后不再出现明文。
|
||
- 任意管理接口响应用测试断言:序列化字符串中不出现 `"body"` 键。
|