Files
MC_Report/docs/API.md
canglan 65edbaf157 refactor: session-based external auth, dynamic sources, drop netease UID
Auth (external API):
- ID: 16-digit random (non-sequential); Secret: SeaReport- + 32 hex
- POST /auth/session: ID+Secret -> Bearer SESSION (24h, single-session,
  old session invalidated on re-issue, disabled client invalidates)
- clientAuth now validates Bearer SESSION via api_sessions JOIN api_clients

Sources (dynamic, no default, open-source friendly):
- sources table + CRUD route (/api/sources, owner; delete guarded by usage)
- users/user_identities.source ENUM -> VARCHAR, seeded netease/skin
- register/admin create/identity bind: validate against enabled sources
- UI: 来源管理 page; source dropdowns loaded dynamically everywhere
  (register, dashboard identity, users admin, bans), labels dynamic

UID removal:
- game_uid/reporter_game_uid no longer required (db default '', validations
  dropped, frontend fields optional)

Docs: EXTERNAL-API.md session flow + new credential format; API.md updated
Verified: 37 checks (syntax, session logic, source CRUD, UID removal, docs)
2026-08-19 20:08:06 +08:00

15 KiB

MC Report System API 文档

面向机器人 / 第三方系统的免登录 API(鉴权方式、请求示例、子服定位语法)见独立文档 EXTERNAL-API.md

Base URL: http://<host>:3100/api

通用约定

说明
认证头 Authorization: Bearer <JWT>(登录后获得)
API 密钥头 x-api-key: <api_key>(安装时生成,注入前端页面,所有请求需携带)
外部密钥头 x-external-key: <external_api_key>(仅 /api/external 插件接口)
内容类型 application/json(文件上传用 multipart/form-data)
错误格式 { "error": "错误信息" }
限流 登录 8/min、注册 3/min、工单 500/min、匿名提交 5/min、全局 300/min

角色:owner(服主) / admin(管理员) / player(玩家)


一、认证 Auth

POST /auth/send-verify-code

发送邮箱验证码(注册前校验邮箱归属)。

{ "email": "player@example.com" }

响应: { "code_id": "uuid", "message": "验证码已发送" }

若 SMTP 未配置,返回 { code_id, code, dev: true }(开发模式直显验证码)。

POST /auth/register

注册账号(需先获取邮箱验证码)。

{
  "username": "player1", "password": "******", "email": "p@example.com",
  "game_name": "Steve", "game_uid": "NETEASE_UID_001",
  "source": "netease",            // netease | skin(皮肤站可不填 UID)
  "captcha_id": "uuid", "captcha_answer": "abcd",
  "code_id": "uuid", "code": "123456"
}

响应 201: { "message": "注册成功,请登录" }

注册时自动在 user_identities 中创建主身份记录。

POST /auth/login

{ "username": "player1", "password": "******" }

响应:

{
  "token": "<JWT>",
  "user": { "id": 1, "username": "player1", "email": "p@example.com",
            "game_name": "Steve", "game_uid": "NETEASE_UID_001",
            "role": "player", "source": "netease" }
}

GET /auth/me (认证)

返回当前用户完整信息,含 identities 数组(全部已绑定身份)。

GET /auth/identities (认证)

列出当前账号绑定的全部身份(一个账号可同时绑定网易端 + 皮肤站)。

响应:

[
  { "id": 1, "source": "netease", "game_name": "Steve", "game_uid": "NETEASE_UID_001", "created_at": "..." },
  { "id": 2, "source": "skin",    "game_name": "Alex",  "game_uid": "SKIN_UUID_002", "created_at": "..." }
]

POST /auth/identities (认证)

绑定新来源身份(同来源仅能绑一个,游戏名全局唯一)。

{ "source": "skin", "game_name": "Alex", "game_uid": "SKIN_UUID_002" }
规则 说明
source 必填,neteaseskin
game_name 必填,不能与其他账号已绑定的游戏名重复
game_uid 网易端必填
同来源重复 拒绝(先删除再重新绑定)
至少保留一个 解绑时若只剩一个身份则拒绝

皮肤站 UUID 自动查询:皮肤站来源时,可通过 GET /settings/uuid-lookup?site=<皮肤站地址>&name=<用户名> 自动获取 UUID(调 Yggdrasil API POST {site}/api/yggdrasil/api/profiles/minecraft,带 SSRF 防护与 10s 超时)。站点皮肤站地址可在系统设置配置,前端绑定弹窗自动带出。

DELETE /auth/identities/:id (认证)

解绑身份。响应: { "message": "已解绑" }

PUT /auth/profile (认证)

更新个人资料(game_name / game_uid / email)。主身份变更会同步到 user_identities

PUT /auth/password (认证)

{ "oldPassword": "旧密码", "newPassword": "新密码" }

POST /auth/forgot-password

{ "email": "p@example.com" }

发送重置链接(使用 reset_password 模板,1 小时有效)。

POST /auth/reset-password

{ "token": "<reset_token>", "password": "新密码" }

POST /auth/verify-email

验证邮箱(token 或 6 位验证码):

{ "code": "<verify_token 或 6 位验证码>" }

二、工单 Tickets

状态机:pending → processing → awaiting_info → resolved / rejected → closed(7天自动关闭);结果申诉 appealing

GET /tickets (认证)

工单列表(带过滤)。Query: type / status / priority / claimed=0|1 / search

  • player: 仅自己的工单
  • admin: 待处理 + 自己接的(建议/投诉管理员/结果申诉不可见)
  • owner: 全部

GET /tickets/stats (认证)

{ "total": 12, "byStatus": { "pending": 3, "processing": 2 } }

GET /tickets/unclaimed (admin/owner)

待认领工单。Query: type

GET /tickets/reported-players (admin/owner)

被举报人聚合统计(次数/处理中/已解决/已驳回/最近时间/常见原因)。

GET /tickets/tracking?token=xxx

凭追踪标识查工单(匿名追踪用,无需登录)。

GET /tickets/:id (认证)

工单详情(含 responses / attachments / transfers / parent_ticket)。

POST /tickets (可选认证)

提交工单(支持匿名;登录用户可选用任一已绑定身份)。

multipart/form-data 或 JSON:

{
  "type": "report",               // report | suggestion | appeal | result_appeal
  "title": "标题",
  "reporter_game_name": "Steve",  // 登录用户可传自己的任一身份,后端校验归属
  "reporter_game_uid": "UID",
  "target_game_name": "Alex",     // 举报必填(与 UID 至少一项)
  "target_game_uid": "UID",
  "reason": "举报原因",            // report/appeal 必填
  "description": "详细描述",       // suggestion/appeal 必填
  "priority": "medium",           // low|medium|high|urgent
  "is_admin_complaint": 0,        // 投诉管理员(仅服主可见)
  "parent_ticket_id": null        // result_appeal 必填(原工单)
}

响应 201: { "id": 8, "tracking_token": "uuid", "message": "提交成功" }(Set-Cookie 留存 tracking_token)

PUT /tickets/:id (admin/owner)

更新状态/优先级/处理备注。

{ "status": "processing", "priority": "high", "claim_note": "内部备注" }

POST /tickets/:id/claim (admin/owner)

接单认领(建议/投诉管理员/结果申诉仅服主可认领)。

{ "claim_note": "内部备注", "initial_reply": "给玩家的初始回复" }

POST /tickets/:id/transfer (admin/owner)

转单。{ "to_user_id": 2, "reason": "原因" }

POST /tickets/:id/response (认证)

回复/补充。{ "content": "内容" }

POST /tickets/:id/anon-response

匿名补充(凭 tracking_token Cookie)。

POST /tickets/batch (admin/owner)

批量操作。{ "ids": [1,2], "action": "delete|status|close", "status": "resolved" }


三、封禁 Bans (owner)

GET /bans、GET /bans/active、GET /bans/min-duration (认证)

封禁列表 / 生效中 / 最短时长校验。

POST /bans (owner)

{ "player_name": "Alex", "player_uid": "UID", "source": "netease|skin",
  "type": "ban|mute|warn|other", "duration": "7天", "reason": "原因",
  "ticket_id": null }

PUT /bans/:id (owner)

更新状态(active|expired|appealed|lifted)/原因/时长。

DELETE /bans/:id (owner)

删除记录。


四、用户管理 Users (admin/owner)

GET /users (admin/owner)、GET /users/:id (admin/owner)

用户列表(含 identity_count 身份数)/ 详情(含 identities 全部身份、管辖子服务器)。

POST /users (admin/owner)

创建用户(自动写入 user_identities 主身份)。角色 owner 仅服主可建。

PUT /users/:id (admin/owner)

更新邮箱/游戏名/UID/来源/角色/状态/密码/管辖服务器。主身份字段变化自动同步 user_identities

POST /users/:id/identities (admin/owner)

管理员为用户绑定额外来源身份(多身份管理)。

{ "source": "skin", "game_name": "Alex", "game_uid": "SKIN_UUID" }

规则同 POST /auth/identities(同来源唯一、游戏名全局唯一、网易端必填 UID)。皮肤站来源同样支持「获取 UUID」辅助查询。

DELETE /users/:id/identities/:identityId (admin/owner)

管理员解绑用户身份(至少保留一个)。

GET /users/:id/servers (admin/owner)

管辖子服务器列表。


五、系统设置 Settings (admin/owner)

端点 说明
GET /settings/settings 全部设置(站点名称/地址/版权/ICP/SMTP)
PUT /settings/settings 批量更新设置
GET /settings/email-templates 邮件模板列表
GET /settings/email-templates/:code 模板详情
PUT /settings/email-templates/:code 更新模板(subject/body,支持 HTML 与 {{变量}})

可用模板: verify_email / email_code / ticket_created / ticket_updated / ticket_claimed / ticket_transferred / reset_password


六、通知 Notifications (admin/owner)

GET/POST /notifications

列表 / 创建 { name, type: "webhook|email", webhook_url, events: "all|ticket_created,..." }

PUT/DELETE /notifications/:id

更新(名称/地址/类型/启用)/删除。

POST /notifications/:id/test

发送测试 Webhook。


七、投票 Polls

端点 认证 说明
GET /polls/groups 认证 分组/子服列表
POST /polls/groups owner 添加分组
DELETE /polls/groups/:id owner 删除分组
GET /polls/active 认证 当前生效投票(按分组聚合,含票数/我的投票)
GET/PUT/DELETE /polls/:id owner 详情/更新/删除
POST /polls owner 创建(≥2选项,同子服仅一个进行中)
POST /polls/:id/vote 认证 投票(管理员 1.5 票权,一人一票)

八、更新内容 Features

端点 认证 说明
GET /features 认证 列表(状态: 待定/计划中/已完成)
POST /features owner 创建
PUT/DELETE /features/:id owner 更新/删除
POST /features/:id/vote 认证 点赞
POST /features/:id/comment 认证 发表评论

九、导出 Export (owner)

端点 说明
GET /export/tickets?type=&status=&start_date=&end_date=&format=csv 工单导出
GET /export/reported-players?format=csv 被举报人统计导出
GET /export/audit-logs?start_date=&end_date=&format=csv 操作日志导出
GET /export/dashboard 控制台统计(总数/类型/状态/今日/用户数/月度趋势)

九·五、日志 Logs (admin/owner)

系统自动记录邮件发送结果、Webhook 调用、服务器错误,后台「系统日志」页可查,方便排查。

端点 说明
GET /logs/emails?status=sent|failed&email=&limit= 邮件日志(收件人/模板/主题/状态/错误)
GET /logs/system?level=info|warn|error&source=&limit= 系统日志(级别/来源/消息/详情)

记录来源:mailer(SMTP 未配置/发送成功/失败)、webhook(拦截内网/非2xx/发送失败)、server(500 错误中间件)。日志写库失败不影响主流程,表自动迁移创建。


十、验证码与文件

端点 说明
GET /captcha SVG 验证码 { id, svg }(5 分钟有效)
GET /uploads/:storedName 附件下载(鉴权;玩家仅可访问自己工单附件)

十一、外部 API(游戏插件 / Java 服务器)

认证:x-external-key: <external_api_key>(安装时生成)。插件登录后可携带 Bearer JWT。

端点 认证 说明
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 过滤)
GET /external/all-tickets/:id client 工单详情(含回复/附件)
GET /external/bans?server=&status=&player= client 拉取封禁列表(可按子服/状态/玩家过滤)
POST /external/bans client 新增封禁(可带 server)
GET /external/reported-players?server= client 被举报统计(可按子服过滤)
GET /external/servers client 服务器列表(含外部别名)
GET /external/stats?server= client 工单统计(可按子服过滤)
POST /external/clients Bearer(owner/admin) 创建 API 客户端,返回 client_id + secret(仅显示一次)
GET /external/clients Bearer(owner/admin) 客户端列表
PUT /external/clients/:id Bearer(owner/admin) 启用/停用客户端
DELETE /external/clients/:id Bearer(owner/admin) 删除客户端

外部鉴权(SESSION 机制)

阶段 请求头 说明
换取 SESSION x-api-client-id + x-api-secret POST /external/auth/session 使用;ID 为 16 位随机数字,Secret 为 SeaReport- + 32 位
后续请求 Authorization: Bearer <SESSION> 所有其余接口;24 小时有效,重换即旧 SESSION 失效,客户端停用立即失效

子服务器定位(server 参数)

每个子服可在「服务器管理」配置外部别名(alias),外部 API 的 server 参数支持三种写法:

  • 别名: survival(推荐,改名不影响)
  • 分组/子服: 网易服务器/生存服
  • 子服名: 生存服(同名时取第一个)

工单/封禁按提交时的 server 归属存储,查询时用同一参数即可精确拉取对应子服数据。


十二、安装与健康

端点 说明
GET /install/status `{ installed: true
POST /install/check-db 测试数据库连接(不存在则自动建库;库名仅字母数字下划线)
POST /install/complete 完成安装:建表 + 创建服主 + 生成密钥(完成后无需重启,自动加载业务路由)
GET /health `{ status: "ok", installed: true

安装流程(两步):check-dbcomplete → 前端自动刷新并跳转登录。


数据兼容与迁移

新增多来源身份功能时,backend/db.jsmigrateAdditions 自动执行(幂等):

  1. 创建 user_identities 表(UNIQUE(user_id, source))
  2. users 表回填主身份:INSERT IGNORE ... SELECT id, source, game_name, game_uid FROM users
  3. 注册/插件注册/管理员创建用户时自动写入主身份记录
  4. 管理员编辑主身份字段时自动同步 user_identities
  5. 工单提交:登录用户可选择任一已绑定身份(后端校验归属);匿名仍走表单字段

老数据无需手工处理,服务启动时自动迁移;users 表原有字段(主身份)保持不变,完全向后兼容。

外部 API 功能新增迁移(幂等,服务启动自动执行):

  1. 创建 api_clients 表(多客户端鉴权)
  2. server_groupsalias 列(子服外部别名)
  3. tickets / bansserver_name 列(按子服归属存储)

老工单/封禁 server_name 为空串,不影响原有查询;新提交的数据自动带子服归属。