# 认证与限流 ## 角色 | 角色 | 能力 | |---|---| | 游客(无 Authorization 头) | 取件、查询元信息;`openUpload=1` 时可上传 | | 管理员(`Authorization: Bearer `) | 全部能力 + `/admin/*` 管理接口 | ## 管理员令牌 - 由 `POST /admin/login` 用管理员密码换取,HS256 JWT,默认有效期 **7 天**(`adminSessionExpire`,1~365 整天,26.9 起由 30 天缩短)。 - 请求头格式:`Authorization: Bearer `。 - **改密/重置管理员密码会轮换 `jwt_secret`,所有已签发令牌立即失效**(401)。 - 密码存储为 bcrypt(cost 12);历史 `sha256$`/明文格式在登录成功后自动升级重哈希,无需手动迁移。 - 游客上传关闭(`openUpload=0`)时,上传类接口也可用管理员 Bearer 令牌通过鉴权。 ## 认证失败语义 | 场景 | 状态码 | |---|---| | `/admin/*` 缺失/无效令牌 | 401 | | `POST /admin/login` 密码错误 | 401(并计入 login 限流) | | 游客上传被关闭且未携带有效令牌 | 403 | | 代理下载 `key` 校验失败 | 403 | ## 未初始化(428) 管理员密码未设置(`admin_token` 为空)时,除 `GET|POST /setup` 与 `GET /api/v1/health` 外全部接口返回 428。 完成 `POST /setup` 初始化后自动解除。 ## 限流规则 限流按 **客户端 IP** 维度(配置 `FCB_TRUSTED_PROXIES` 声明可信代理 CIDR,命中时解析 `X-Forwarded-For` 取真实 IP), 窗口计数原子化存储于缓存(未配置 Redis 时为进程内存)。**超限一律返回 423**: ```json { "code": 423, "msg": "请求次数过多,请稍后再试" } ``` | 规则 | 生效端点 | 计数时机 | 默认 | 配置键 | |---|---|---|---|---| | `upload` | `/share/text`、`/share/file`、`/chunk/upload/*`、`/presign/upload/*` | **成功后**计数(进入时仅检查) | 10 次 / 1 分钟 | `uploadCount`、`uploadMinute` | | `error` | `/share/select`、`/share/download` | 取件失败(不存在/过期/鉴权失败)时计数 | 10 次 / 1 分钟 | `errorCount`、`errorMinute` | | `login` | `/admin/login` | 登录失败时计数 | 5 次 / 15 分钟 | `loginCount`、`loginMinute` | | `metadata` | `/share/metadata` | **每次访问即计数**(含失败) | 同 `error` | `errorCount`、`errorMinute` | - 规则值可由管理端 `PATCH /admin/config/update` 运行时修改,立即生效(无需重启)。 - 取件成功(`/share/select`、`/share/download`)不计入 `error` 限流。 ## 代理下载令牌(key) `GET /share/download` 的 `key` 由服务端按窗口生成: `sha256(code + timeFactor + "000" + jwt_secret)`,`timeFactor = unix秒 / 1000`(约 16.7 分钟一个窗口)。 服务端**同时接受当前与上一窗口**的令牌,避免窗口边界竞态。令牌通过 `POST /share/select` 的响应 `download_url` 下发,客户端不应自行构造。 ## 示例 登录获取令牌: ```bash curl -s http://localhost:8466/admin/login \ -H 'Content-Type: application/json' \ -d '{"password":"your-admin-password"}' ``` ```json { "code": 200, "msg": "ok", "data": { "id": "admin", "username": "admin", "token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_at": 1750000000, "expires_in": 604800 } } ``` 携带令牌调用管理接口: ```bash TOKEN="eyJhbGciOiJIUzI1NiIs..." curl -s http://localhost:8466/admin/dashboard -H "Authorization: Bearer $TOKEN" ``` 校验令牌是否有效: ```bash curl -s http://localhost:8466/admin/verify -H "Authorization: Bearer $TOKEN" ``` ```json { "code": 200, "msg": "ok", "data": { "id": "admin", "username": "admin", "token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_at": 1750000000 } } ``` 令牌失效时: ```json { "code": 401, "msg": "令牌无效或已过期" } ```