Files
alist-serve-resource/docs/PERMISSIONS.md
T
hoelee 80eb2b71be docs: architecture, permissions, admin guide + refresh schema/workflows
- New ARCHITECTURE.md (3-layer model + data flow + lifecycle matrix)
- New PERMISSIONS.md (grant calculation rules + enforcement)
- New ADMIN_GUIDE.md (華文极简:Customer/CustomerProduct 授权 + Product/Resource 管理)
- Rewrite N8N_WORKFLOWS.md from WF1-6 (obsolete) to actual W1/W2/W3
- Update DATABASE_SCHEMA.md: fix status enum (drop 'disabled'), add 5-status semantics
- Update README.md doc index
2026-08-23 07:30:41 +08:00

60 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 权限模型说明(Permissions)
> 本文解释「最终生效的 AList 权限」是怎么从 NocoDB 数据算出来的。更新日期 2026-08-23。
## 最终生效权限的三要素
一个客户最终能访问哪些 AList 路径,由三样东西决定:
1. `Customers.status` — 整户开关(account-level)
2. `CustomerProducts` — 买了哪些产品 + 何时到期(product entitlement)
3. `Product → Resources` — 每个产品包含哪些路径(M2M),资源有 `alist_path`
三者合起来 → n8n 调 `calculateEffectiveGrants` → 算出 desired scopes → 写到 AList Role。
## 计算规则(calculateEffectiveGrants)
对某个客户,desired scopes = 以下两类的**并集**:
### (A) CustomerProduct 派生
遍历该客所有 CustomerProduct:
- 跳过 `status != active` 的
- 跳过 `expires_at <= 今天` 的(**到期当天视为已过期**)
- 通过 `product` link → Product 的 M2M Resources → 拿到每个 resource 的路径
### (B) AccessGrant 派生(预留,当前不经 n8n 写入)
- 同 (A),跳过非 active / 已过期
### 合并规则
- 同一个 path 来自多个来源 → 取 **MAX(expires_at)**(两个产品共享一个资源时,取较晚的到期)
- permission:`readwrite` 覆盖 `read`(readwrite=1,否则 0)
- basis:本系统客户一律 **只读**(permission 0),读写在 AccessGrant 手工授权时可用
## AList 侧落地(enforcement)
- 每个客户 = 1 个专属 AList Role(`name = customer-<username>`)
- Role 的 `permission_scopes` = desired scopes 的绝对路径数组
- 客户 User:`base_path = '/'`(**必须 `/`**,否则 JoinPath 双重前缀 → 全 403)
- 客户 User:`permission = 16384`(bit 14 = Check path limit 置位 → 只能访问 role scope 内的路径)
- `disabled` 由 status 控制:非 active → `disabled=true`
## 多文件夹授权正确做法(已实测)
- `base_path = "/"` + role scope 用**绝对路径**(如 `/Class/Forex`、`/Template/Music`)
- 结果:客户只看到被授权路径,未授权挂载点(`/Book` 等)不泄露
## 到期与状态的关系
| 场景 | 结果 |
|---|---|
| CustomerProduct 到期 | 该产品派生的路径从 scopes 移除(W2/W3 对账自动修)|
| 整个 Customer status 变 non-active | 整户 disable + scopes 清空(W1)|
| non-active → active 恢复 | 重算当前有效 scopes,**不恢复已过期产品** |
## 重要边界
- `Customers.status` 是账户级开关,**不替代** CustomerProduct 的到期。
- 例:Customer = `expired`,其 Product A 仍 active 且未到期。恢复 `expired → active` 后 Product A 会自动回来;已过期的 Product B 不会回来。
- 状态变化**不自动改** CustomerProducts(不批量改 CP.status、不改 expires_at、不删除 CP)。
- AccessGrants 历史记录**不删除**;恢复时重算,不用旧 AccessGrant scope 直接恢复。