鉴权
请求头格式
X-CR4-Authorization: Bearer <cloudreve_access_token>
优先用专属头 X-CR4-Authorization——避免与反向代理 / WAF 等基础设施冲突,也便于区分 “给 cr4sync 的 token” 与 “给 cloudreve 的 token”。
缺失时回退标准 Authorization 头:cr4sync 作为 cloudreve 扩展同源部署时,前端复用 cloudreve 登录态直接带标准 Authorization 更自然;标准客户端(curl 等)也可用标准头访问。两者都在时以 X-CR4-Authorization 为准。
取 token 顺序: X-CR4-Authorization → (缺失) Authorization → (都缺) 401
若
X-CR4-Authorization存在但格式非法(非Bearer <token>),直接判 401,不静默回退到Authorization——专属头一旦显式出现就以它为准。
鉴权流程
┌─────────────────────────────────────────┐
│ middleware/auth.rs │
│ 1. 取 X-CR4-Authorization (缺回退 Authorization) │
│ 2. 解析 Bearer 前缀 │
│ 3. base64 解 JWT payload (不验签) │
│ - 取 sub (user_id) │
│ - 校验 exp 未过期 │
│ 4. AuthValidator.validate(token) │
│ - moka cache.get(token) │
│ - hit → 返 AuthResult │
│ - miss → GET cr4/user/info/{sub} │
│ header: Authorization=... │
│ → 200 + body.code=0 → │
│ is_admin = │
│ admin_groups contains │
│ data.group.name │
│ db.upsert_user(...) │
│ cache TTL = min(60s, │
│ exp - now - 30s) │
│ 5. 注入 AuthContext 到 extension │
└─────────────────────────────────────────┘
AuthContext
注入到 axum request extension,handler 用 Extension<AuthContext> 取:
#![allow(unused)]
fn main() {
pub struct AuthContext {
pub user_id: String, // Cloudreve sub
pub is_admin: bool, // group.name 命中 admin 组名集合
pub token: String, // 原始 access_token (现场上传 Cloudreve 时用)
pub group_name: String, // 用户组名
pub email: Option<String>,
pub nickname: Option<String>,
}
}
缓存
AuthValidator 内置 moka::future::Cache<String, AuthResult>:
| 维度 | 值 |
|---|---|
| key | 原始 access_token |
| TTL | min(60s, jwt.exp - now - 30s) |
| 容量 | 默认 10000 entry |
也即:token revoke 后 cr4sync 端最多 60s 后感知,admin 角色变更同理。
admin 自动识别
cr4sync 不维护自己的 admin 列表。每次 /user/info 响应都看 data.group.name,并与 admin 组名集合比对:
{
"code": 0,
"data": {
"id": "sub-xxx",
"email": "a@example.com",
"nickname": "Alice",
"group": {
"name": "管理员"
}
}
}
默认 admin 组名集合包含 "Admin" 和 "管理员",任一命中即 is_admin = true。如果 [serve.cr4].admin_group 配了值,则只认该配置值。
require_admin middleware
/admin/* 子树路由额外挂 require_admin middleware:从 extension 取 AuthContext,is_admin == false ⇒ ApiError::Forbidden(HTTP 403 + envelope.code=1000)。
白名单
/api/v4/cr4sync/health不需要鉴权。embed-web构建下/extensions/cr4sync(内嵌前端 SPA 静态资产)不走鉴权——前端加载后再用 token 调 API。详见 部署。
鉴权失败回执
| 现象 | HTTP | envelope |
|---|---|---|
| 头缺失 (X-CR4-Authorization / Authorization 都无) / 非 Bearer | 401 | { code: 1000, msg: "...", data: null, request_id } |
| JWT base64 解失败 | 401 | { code: 1000, msg: "invalid token format", ... } |
| JWT exp 已过 | 401 | { code: 1000, msg: "token expired", ... } |
| Cloudreve /user/info 返非 0 code | 401 | { code: <cloudreve.code>, msg: <cloudreve.msg>, ... } 透传 |
| Cloudreve /user/info 网络失败 | 500 | { code: 3000, msg: "upstream unavailable", ... } |
非 admin 访问 /admin/* | 403 | { code: 1000, msg: "admin required", ... } |
与 Cloudreve token 流转
仅鉴权时使用调用方的 access_token 校验身份;后续上传 Cloudreve 也强制使用调用方 token,绝不读站长 token.json。详见 Migrate 接口 的“长任务 token 续期“段。