别名配置
在 Yao 引擎的 ACL(访问控制列表)设计架构中,features/alias.yml 和 scopes/alias.yml 虽然都使用了“别名(Alias)”这一概念来进行分组管理,但它们分别作用于完全不同的应用层级:前端表现层与后端数据层。
简单来说:features 决定用户能“看见”什么,而 scopes 决定用户能“执行”什么。
以下是详细的对比分析:
1. features/alias.yml (前端特性组)
这个文件位于 openapi/features/alias.yml,它属于 Feature Flag(特性开关) 系统的一部分。
- 核心作用:UI 组件的可见性控制。 它将多个原子特性(Feature)打包成一个更易管理的组。这些配置最终会通过 API 返回给前端,前端根据这些标记来决定是否渲染某个菜单、按钮或页面区块。
- 配置对象:针对的是“功能点”或“界面元素”。
- 安全性:低。这只是一种展示逻辑。如果后端没有对应的保护,用户可以通过直接调用 API 绕过前端限制。
配置示例分析:
yaml
# 定义一个名为 profile:manage 的别名
profile:manage:
- profile:read # 原子特性:查看个人资料页
- profile:edit # 原子特性:显示编辑按钮
# 定义一个更高级的别名 user:full,包含上述别名
user:full:
- profile:manage # 嵌套引用
- team:manage实际应用场景: 前端调用 /api/v1/features 获取当前用户的特性列表。如果返回了 profile:edit,前端 React/Vue 组件就会渲染“编辑”按钮;否则该按钮隐藏。
2. scopes/alias.yml (后端权限组)
这个文件位于 openapi/scopes/alias.yml,它属于 OAuth2 / RBAC(基于角色的访问控制) 系统的一部分。
- 核心作用:API 端点的数据安全与访问控制。 它将多个原子权限(Scope)打包成一个组。这些配置被后端
ScopeManager加载,用于在请求到达 API 处理器之前进行拦截和校验。 - 配置对象:针对的是“API 资源”和“HTTP 动作”(如 GET, POST)。
- 安全性:高。这是系统的最后一道防线。无论前端是否显示了按钮,只要请求不包含正确的 Scope,后端都会拒绝执行并返回
403 Forbidden。
配置示例分析:
yaml
# 定义名为 kb:own 的权限组,允许操作自己的知识库
kb:own:
- collections:read:own # 允许 GET /kb/collections/own
- collections:write:own # 允许 POST /kb/collections/own
- documents:read:own
# 系统管理员权限,使用通配符
system:root:
- '*:*:*'实际应用场景: 当用户发起 POST /kb/collections 请求时,Yao 引擎的中间件(Middleware)会检查该用户的角色是否拥有 collections:write 相关的 Scope。如果没有,请求会被立即拦截。
3. 核心差异对比表
| 维度 | features/alias.yml | scopes/alias.yml |
|---|---|---|
| 作用域 | 前端 (Frontend) | 后端 (Backend) |
| 控制对象 | UI 界面、菜单、按钮 | API 接口、数据库读写 |
| 验证逻辑 | if (features["profile:edit"]) | acl.Enforce(c) (中间件自动执行) |
| 失败后果 | 用户看不到按钮 (UI 隐藏) | 请求报错 403 Forbidden (访问拒绝) |
| 数据约束 | 不涉及数据过滤 | 支持 owner: true 等数据行级过滤 |
| 主要目的 | 用户体验 (UX)、功能分级 | 数据安全 (Security)、防御 |
4. 为什么需要两套配置?(最佳实践)
Yao 采用这种分离设计是为了实现最大程度的灵活性和解耦:
- 灰度发布/功能开关:你可能已经开发好了后端的 API (Scope 已配置),但希望只对 10% 的用户开放入口。此时,你只需要在
features中限制该功能,而无需修改后端安全策略。 - 多端适配:移动端和 Web 端可能共用一套后端 API (Scopes 相同),但界面功能完全不同 (Features 不同)。
- 细粒度控制:
- Feature:
team:view(只控制是否能看到团队菜单)。 - Scope:
team:read:basic(只读基础信息),team:read:sensitive(读取敏感薪资信息)。 - 这种分离允许前端只有一个入口,但后端根据权限返回不同详细程度的数据。
- Feature:
总结:
- 修改
features/alias.yml是为了告诉前端:“这群人能看到这些菜单”。 - 修改
scopes/alias.yml是为了告诉后端:“这群人能调用这些接口”。
在实际开发中,当你添加一个新模块时,通常需要在 scopes 中定义它的 API 安全规则,同时在 features 中定义它的 UI 入口,并在各自的 alias.yml 中进行分组,最后分配给 Role。