# 管理后台 API 管理端接口:除 `POST /admin/login` 与初始化向导 `/setup` 外,一律要求 `Authorization: Bearer `(见《认证与限流》),无效令牌 401。 ## 初始化向导:GET /setup 未初始化时返回 HTML 配置页(站点名称、管理员密码、上传/限流/保存策略); 已初始化时 `303` 重定向到 `/`。 ```bash curl -i http://localhost:8466/setup ``` ## 初始化提交:POST /setup 表单(浏览器向导)或 JSON 均可;成功后写入库配置 KV 并生成密码哈希与 `jwt_secret`。 表单提交返回成功 HTML 页;JSON 提交返回 JSON。 **主要字段**: | 字段 | 必需 | 默认 | 说明 | |---|---|---|---| | `admin_password` | ✅ | - | 管理员密码(≥8 位) | | `confirm_password` | ✅ | - | 确认密码(须一致) | | `site_name` | ❌ | 文件快传 | 站点名称 | | `upload_size_value` / `upload_size_unit` | ❌ | 10 / MB | 单文件大小限制(单位 KB/MB/GB) | | `save_time_value` / `save_time_unit` | ❌ | 0 / day | 最长保存秒数(0=不限) | | `expireStyle` | ❌ | day,hour,minute,forever,count | 过期方式(可多值/逗号分隔) | | `code_generate_type` | ❌ | secret | 取件码类型 `number`/`secret` | | `errorCount` / `errorMinute` | ❌ | 10 / 1 | 取件错误限流 | | `loginCount` / `loginMinute` | ❌ | 5 / 15 | 登录失败限流 | | `uploadCount` / `uploadMinute` | ❌ | 10 / 1 | 上传限流 | | `allowed_file_types` | ❌ | `*` | 逗号分隔白名单 | | `openUpload` / `enableChunk` | ❌ | 1 / 0 | 游客上传 / 分片开关(`1`/`true`/`on`/`yes`) | ```bash curl -s -X POST http://localhost:8466/setup \ -H 'Content-Type: application/json' \ -d '{"admin_password":"admin12345","confirm_password":"admin12345","site_name":"我的文件柜","upload_size_value":10,"upload_size_unit":"MB"}' ``` ```json { "code": 200, "msg": "ok", "data": { "ok": true, "admin": "/#/admin" } } ``` **错误响应**(400,HTML 表单时内嵌错误提示): ```json { "code": 400, "msg": "管理员密码至少 8 位" } ``` ## 登录:POST /admin/login ```bash curl -s -X POST http://localhost:8466/admin/login \ -H 'Content-Type: application/json' \ -d '{"password":"admin12345"}' ``` **成功响应**(200): ```json { "code": 200, "msg": "ok", "data": { "id": "admin", "username": "admin", "token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_at": 1750000000, "expires_in": 604800 } } ``` **错误响应**: ```json { "code": 401, "msg": "密码错误" } ``` ```json { "code": 423, "msg": "请求次数过多,请稍后再试" } ``` ## 校验会话:GET /admin/verify ```bash curl -s http://localhost:8466/admin/verify -H "Authorization: Bearer $TOKEN" ``` ```json { "code": 200, "msg": "ok", "data": { "id": "admin", "username": "admin", "token": "eyJ…", "token_type": "Bearer", "expires_at": 1750000000 } } ``` ## 登出:POST /admin/logout 无状态 JWT,服务端仅返回确认(客户端应丢弃令牌): ```json { "code": 200, "msg": "ok", "data": { "ok": true } } ``` ## 仪表盘:GET /admin/dashboard ```bash curl -s http://localhost:8466/admin/dashboard -H "Authorization: Bearer $TOKEN" ``` ```json { "code": 200, "msg": "ok", "data": { "totalFiles": 42, "storageUsed": "123456789", "sysUptime": 1750000000000, "yesterdayCount": 5, "yesterdaySize": "1048576", "todayCount": 12, "todaySize": "5242880", "activeCount": 40, "expiredCount": 2, "textCount": 10, "fileCount": 32, "chunkedCount": 3, "usedCount": 156, "storageBackend": "local", "uploadSizeLimit": 10485760, "openUpload": 1, "enableChunk": 1, "maxSaveSeconds": 0, "topSuffixes": [ { "suffix": ".pdf", "count": 12 }, { "suffix": "Text", "count": 10 } ], "recentFiles": [ { "id": 42, "code": "K3P9W", "name": "report.pdf", "size": 1048576, "created_at": "2025-06-01T12:00:00+08:00", "expired_at": "2025-06-08T12:00:00+08:00", "is_expired": false, "expired_count": -1, "used_count": 3, "is_text": false, "is_chunked": false, "is_permanent": false, "has_download_limit": false, "remaining_downloads": null, "file_hash": null, "prefix": "report", "suffix": ".pdf", "text": false, "createdAt": "2025-06-01T12:00:00+08:00", "expiredAt": "2025-06-08T12:00:00+08:00", "isExpired": false, "expiredCount": -1, "usedCount": 3, "isText": false, "isChunked": false, "isPermanent": false, "hasDownloadLimit": false, "remainingDownloads": null, "fileHash": null } ], "recentActivities": [] } } ``` > `storageUsed`/`todaySize`/`yesterdaySize` 为字符串字节数;`sysUptime` 为服务启动时刻的 Unix 毫秒。 ## 文件列表:GET /admin/file/list **参数**: | 参数 | 默认 | 说明 | |---|---|---| | `page` / `size` | 1 / 10 | 分页(size 1~100) | | `keyword` | - | 模糊匹配取件码/文件名/哈希/文本内容 | | `status` | - | `active` / `expired` | | `type` | - | `text` / `file` / `chunked` | | `sortBy` | `created_at` | `created_at`/`expired_at`/`name`/`size`/`used_count`/`code` | | `sortOrder` | `desc` | `asc` / `desc` | ```bash curl -s "http://localhost:8466/admin/file/list?page=1&size=10&status=active&sortBy=size&sortOrder=desc" \ -H "Authorization: Bearer $TOKEN" ``` ```json { "code": 200, "msg": "ok", "data": { "page": 1, "size": 10, "total": 40, "summary": { "totalFiles": 42, "activeCount": 40, "expiredCount": 2, "textCount": 10, "fileCount": 32, "chunkedCount": 3, "storageUsed": 123456789, "usedCount": 156 }, "data": [ { "id": 42, "code": "K3P9W", "name": "report.pdf", "prefix": "report", "suffix": ".pdf", "size": 1048576, "is_text": false, "is_chunked": false, "is_expired": false, "expired_at": "2025-06-08T12:00:00+08:00", "expired_count": -1, "used_count": 3, "created_at": "2025-06-01T12:00:00+08:00", "has_download_limit": false, "is_permanent": false, "remaining_downloads": null, "file_hash": null, "text": false, "isText": false, "isChunked": false, "isExpired": false, "expiredAt": "2025-06-08T12:00:00+08:00", "expiredCount": -1, "usedCount": 3, "createdAt": "2025-06-01T12:00:00+08:00", "hasDownloadLimit": false, "isPermanent": false, "remainingDownloads": null, "fileHash": null } ] } } ``` ## 文件详情:GET /admin/file/detail `GET ?id=42` 或 `POST {"id":42}`。返回列表条目字段;文本分享额外含 `content`(全文)。 ```json { "code": 200, "msg": "ok", "data": { "id": 42, "code": "K3P9W", "name": "report.pdf", "size": 1048576, "is_text": false, "expired_at": "2025-06-08T12:00:00+08:00", "expired_count": -1, "used_count": 3, "created_at": "2025-06-01T12:00:00+08:00", "file_hash": null } } ``` ```json { "code": 404, "msg": "文件不存在" } ``` ## 更新文件:PATCH /admin/file/update 更新取件码/文件名(前后缀)/过期策略。**PATCH 为主名,POST 为兼容别名**。 **请求体**: | 字段 | 类型 | 说明 | |---|---|---| | `id` | int | 必需 | | `code` | string | 新取件码(冲突 400「code已存在」) | | `prefix` / `suffix` | string | 文件名前后缀 | | `expired_at` | string | 过期时间(ISO 8601,如 `2025-07-01T00:00:00+08:00`) | | `expired_count` | int | 取件次数上限(`-1` 按时间/永久) | ```bash curl -s -X PATCH http://localhost:8466/admin/file/update \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"id":42,"expired_at":"2025-07-01T00:00:00+08:00","expired_count":10}' ``` ```json { "code": 200, "msg": "ok", "data": "更新成功" } ``` ```json { "code": 400, "msg": "code已存在" } ``` ## 删除文件:DELETE /admin/file/delete 删除分享记录并连带删除存储文件(文本分享无存储文件)。`DELETE` 或 `POST`,请求体 `{"id":42}`。 ```bash curl -s -X DELETE http://localhost:8466/admin/file/delete \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"id":42}' ``` ```json { "code": 200, "msg": "ok", "data": null } ``` ```json { "code": 400, "msg": "请选择要删除的文件" } ``` ## 批量删除:POST /admin/file/batch-delete `POST` 或 `DELETE`,请求体 `{"ids":[41,42,43]}`。返回逐条统计: ```json { "code": 200, "msg": "ok", "data": { "requestedCount": 3, "deletedCount": 2, "missingCount": 1, "failedCount": 0, "deleted": [41, 42], "missing": [43], "failed": [], "requested_count": 3, "deleted_count": 2, "missing_count": 1, "failed_count": 0 } } ``` ## 批量更新:PATCH /admin/file/batch-update `PATCH` 或 `POST`。请求体:`ids[]` 必需;`expired_at`(ISO 8601)/`expired_count` 二选一; `clearExpiredAt: true`(或 `clear_expired_at`)= 清空过期时间并置 `expired_count=-1`(永久)。 ```bash curl -s -X PATCH http://localhost:8466/admin/file/batch-update \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"ids":[41,42],"clearExpiredAt":true}' ``` ```json { "code": 200, "msg": "ok", "data": { "requestedCount": 2, "updatedCount": 2, "missingCount": 0, "failedCount": 0, "updated": 2, "missing": [], "failed": [], "requested_count": 2, "updated_count": 2, "missing_count": 0, "failed_count": 0 } } ``` ## 过期策略动作:PATCH /admin/file/policy-action 对单个文件执行快捷策略。`PATCH` 或 `POST`。批量版为 `/admin/file/batch-policy-action`(`{"ids":[…]}`),响应结构同批量更新。 **请求体**: | 字段 | 说明 | |---|---| | `id` | 文件 ID | | `action` | `extend_24h` / `extend_7d` / `make_permanent` / `reset_download_limit` | | `downloadLimit` | 仅 `reset_download_limit` 用:新取件次数(默认 5,须 >0) | ```bash curl -s -X PATCH http://localhost:8466/admin/file/policy-action \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"id":42,"action":"reset_download_limit","downloadLimit":3}' ``` ```json { "code": 200, "msg": "ok", "data": { "id": 42, "action": "reset_download_limit" } } ``` ```json { "code": 400, "msg": "不支持的策略动作" } ``` > `extend_24h`/`extend_7d` 在当前过期时间(未过期时)基础上顺延;`make_permanent` 清空过期时间并置次数 -1。 ## 管理员下载:GET /admin/file/download?id= 下载原文件(**不消耗取件次数**);文件返回二进制流(支持 Range),文本分享返回 JSON(`data` 为文本内容)。 ```bash curl -s -OJ "http://localhost:8466/admin/file/download?id=42" -H "Authorization: Bearer $TOKEN" ``` ## 文本预览:GET /admin/file/preview 仅文本分享可用(文件分享返回 400)。`maxChars` 截断长度(默认 4000,1~20000)。 ```bash curl -s "http://localhost:8466/admin/file/preview?id=41&maxChars=100" -H "Authorization: Bearer $TOKEN" ``` ```json { "code": 200, "msg": "ok", "data": { "id": 41, "code": "8XQ2M", "name": "Text.txt", "type": "text", "content": "你好,文件快传", "length": 24, "previewLength": 24, "truncated": false, "maxChars": 100, "max_chars": 100, "created_at": "2025-06-01T12:00:00+08:00", "createdAt": "2025-06-01T12:00:00+08:00" } } ``` ```json { "code": 400, "msg": "仅文本分享支持预览" } ``` ## 读取配置:GET /admin/config/get 返回运行时配置 KV(含默认值与管理端修改)。`admin_token` 恒返回空串(屏蔽); `jwt_secret` 不下发;存储引擎为进程级单例,`_engine_hint` 提示引擎配置修改需重启。 26.9 新增键(需求 ①②③④⑩)一并返回:`background_url`、`footer_text`、`footer_beian`、 `notify_enabled`、`max_save_count`、`max_file_size` 等。 ```json { "code": 200, "msg": "ok", "data": { "site_name": "文件快传", "name": "文件快传", "description": "开箱即用的文件快传系统", "page_explain": "…", "keywords": "…", "notify_title": "系统通知", "notify_content": "…", "notify_enabled": 1, "logo_url": "", "favicon_url": "", "background_url": "", "footer_text": "", "footer_beian": "", "openUpload": 1, "uploadSize": 10485760, "max_file_size": 0, "max_save_count": 0, "allowed_file_types": ["*"], "expireStyle": ["day","hour","minute","forever","count"], "code_generate_type": "secret", "enableChunk": 1, "uploadMinute": 1, "uploadCount": 10, "errorMinute": 1, "errorCount": 10, "loginCount": 5, "loginMinute": 15, "max_save_seconds": 0, "storageLimit": 0, "opacity": 0.9, "background": "", "showAdminAddr": 0, "robotsText": "User-agent: *\nDisallow: /", "adminSessionExpire": 604800, "storage_path": "", "local_storage_path": "/app/data", "file_storage": "local", "admin_token": "", "_engine_hint": { "storage_backend": "local", "note": "存储引擎为进程级单例,修改存储引擎相关配置后需重启服务生效" } } } ``` ## 存储引擎热切换:POST /admin/storage/switch(26.9) 运行时切换存储引擎,**无需重启**: ```bash curl -s -X POST http://localhost:8466/admin/storage/switch \ -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ -d '{"engine":"s3"}' # 成功:{"code":200,"msg":"ok","data":{"ok":true,"engine":"s3"}} # 失败:503 {"code":503,"msg":"存储引擎切换失败,已保持原引擎: …"} ``` - `engine` 仅接受 `local|s3|webdav`(400 中文错误)。 - 切换流程:用最新 KV 参数构建新引擎 → 健康检查 → 通过才替换当前引擎并持久化 `storage_engine`。 - 失败(构建/健康检查不过)返回 503,**原引擎与 KV 均保持不变**。 - 切到当前引擎为幂等操作(直接返回 200)。 - 旧文件按归属引擎(`file_codes.engine`)取回,切换后旧引擎文件仍可下载。 ## 更新配置:PATCH /admin/config/update 部分更新(JSON 对象,未提供的键不变;表单亦可)。**PATCH 为主名,POST 为兼容别名**。 - 仅接受管理端可见键(见上响应键集合),未知键忽略。 - 数值型键自动转型:`openUpload`、`enableChunk`、`uploadSize`、`storageLimit`、限流四组、`max_save_seconds`、`adminSessionExpire`、`showAdminAddr`;26.9 新增 `max_save_count`、`max_file_size`、`notify_enabled`;`opacity` 为浮点。 - **26.9**:`site_domain`(站点对外域名)可经本端点设置,非法格式 400(仅 http/https、主机+端口、不带路径)。 - **26.9 引擎键**:`storage_engine` 不经本端点修改(走 `POST /admin/storage/switch`);引擎参数键 (`local_storage_path`、`webdav_url`、`webdav_root_path`、`webdav_username`、`webdav_password`、 `s3_endpoint_url`、`s3_region_name`、`s3_bucket_name`、`s3_access_key_id`、`s3_secret_access_key`、 `aws_session_token`、`s3_addressing_style`)可经本端点保存——保存后对应引擎实例缓存失效, 下次切换/构建生效;敏感键空串或 `******` 表示不修改。 - **26.9 schema 校验**(`settings.KVSchema`,越界一律 400,中文错误信息): - 整型边界:`max_file_size` ≤ 10GiB(10737418240)、`max_save_count` ≤ 100000、`max_save_seconds` ≤ 31536000(365 天)、`notify_enabled` ∈ {0,1}、`uploadCount` 1~10000、`uploadMinute` 1~1440 等; - 字符串长度:`background_url` ≤ 2048、`footer_text` ≤ 2000、`footer_beian` ≤ 128、`notify_title` ≤ 128、`notify_content` ≤ 2000 字符; - 列表键 `expireStyle` / `allowed_file_types`:须为字符串数组(或逗号分隔串)且至少保留一项; - 错误示例:`{"code":400,"msg":"max_file_size 必须是整数"}`、`{"code":400,"msg":"max_file_size 不能大于 10737418240"}`、`{"code":400,"msg":"footer_beian 长度不能超过 128 字符"}`、`{"code":400,"msg":"notify_enabled 不能大于 1"}`。 - `background_url` 协议白名单(需求 ①,防 `javascript:` 注入):仅 `http(s)://`、`data:image/*` 与站内相对路径(`/`开头);空串=清除背景。非法值 400: `{"code":400,"msg":"background_url 仅支持 http(s) 地址、data:image 图片或站内相对路径"}` - `admin_token`:明文密码自动哈希,**并轮换 `jwt_secret`(全部管理员令牌立即失效)**;空串忽略;已是哈希格式则原样保存。 - `adminSessionExpire` 须为 1~365 的整天秒数(86400 的整数倍),否则 400。 - `storageLimit` 不能小于 0。 - 修改限流/策略配置**立即生效**(无需重启:限流规则运行时同步,策略由上传链路每次实时读取);引擎相关(`file_storage`/`s3_*`/`webdav_*`/`storage_path`/`local_storage_path`)需重启。 ```bash curl -s -X PATCH http://localhost:8466/admin/config/update \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"site_name":"我的文件柜","uploadSize":52428800,"openUpload":1,"footer_beian":"京ICP备20240001号","max_file_size":10485760,"max_save_count":5}' ``` ```json { "code": 200, "msg": "ok", "data": { "ok": true } } ``` ```json { "code": 400, "msg": "adminSessionExpire 必须是 1 到 365 个整天" } ``` ```json { "code": 400, "msg": "background_url 仅支持 http(s) 地址、data:image 图片或站内相对路径" } ``` ## 修改管理员密码:PATCH /admin/settings/password `PATCH` 或 `POST`。新密码 ≥8 位;成功后哈希保存并**轮换 `jwt_secret`,所有旧令牌失效(401)**,需重新登录。 ```bash curl -s -X PATCH http://localhost:8466/admin/settings/password \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"old_password":"admin12345","new_password":"new-pass-6789"}' ``` ```json { "code": 200, "msg": "ok", "data": { "ok": true } } ``` ```json { "code": 400, "msg": "新密码长度至少 8 位" } ``` ```json { "code": 401, "msg": "旧密码错误" } ``` ## 手动回收:POST /admin/recycle/run **26.9**:手动触发一轮过期分享回收(定时循环之外的管理端入口)。回收范围: 时间已过期、次数已耗尽、创建时间超过 `retention_days` 的分享——删除记录并 连带删除存储对象(SHA512 去重开启时做引用计数,仍有其他分享引用的对象保留)。 ```bash curl -s -X POST "http://localhost:8466/admin/recycle/run" -H "Authorization: Bearer $TOKEN" ``` ```json { "code": 200, "msg": "ok", "data": { "removed": 3 } } ``` 相关配置键:`recycle_enabled`(定时开关)、`recycle_interval`(扫描间隔)、 `retention_days`(最长存储时长)、`dedup_enabled`(引用计数开关)。