进一步的理解yao 框架中的openapi权限 角色配置
基于https://github.com/YaoApp/yao-dev-app的 openapi 目录下的配置文件,详细解析 Yao 框架的权限与角色配置逻辑:
1. 核心架构:三层权限模型
Yao 的权限系统可以看作是一个漏斗模型,请求需要依次通过以下三层验证:
- 认证层 (Authentication): 由
openapi.yao定义,决定“你是谁”。 - 范围层 (Scopes): 由
scopes/*.yml定义,决定“特定的 API 端点对应什么权限标识”。 - 角色层 (RBAC): 由
roles.json定义,决定“这个角色拥有哪些权限标识”。
2. 详细配置解析
第一层:全局入口与安全配置 (openapi.yao)
这是 OpenAPI 的主配置文件,它定义了整个 API 服务的“安保系统”。
- OAuth2 集成: 文件中详细配置了
oauth模块,包括证书签名 (signing)、令牌生命周期 (token) 和安全策略 (security)。- 关键点:
oauth.features.oauth21_enabled: true表明它默认启用了更安全的 OAuth 2.1 标准(这就要求了pkce_required: true)。
- 关键点:
- 服务提供者:
providers字段定义了用户数据来源 (__yao.user) 和 OAuth 客户端存储 (__yao.oauth.client),这通常对应 Yao 的 Model 或 Store。 - 安全策略:
security.rate_limit_enabled允许你配置限流,防止暴力破解。
第二层:权限范围定义 (scopes/)
这一层是将HTTP URL映射为逻辑权限字符串的地方。Yao 的 DSL 解析器会读取这些配置来生成路由守卫。
全局规则 (
scopes/scopes.yml):default: deny: 安全最佳实践。默认拒绝所有未明确定义的请求,这是“零信任”的基础。public: 定义了白名单,例如/user/entry(登录接口),这些接口不需要 Token 即可访问。endpoints: 这里可以进行粗粒度的控制(如直接allow或deny),适用于不需要复杂权限判断的内部接口。
细粒度资源范围 (如
scopes/agent/agents.yml): 这是 Yao 权限系统最强大的地方。它不仅定义了权限,还定义了数据的所有权上下文。agents:read:all: 允许访问GET /agent/agents。这是一个管理级权限。agents:read:own:- 对应
GET /agent/agents/own。 - 关键属性
owner: true: 当用户拥有此 scope 时,Yao 引擎不仅检查 URL 匹配,还会自动注入上下文过滤器,确保用户只能查询到owner_id等于当前用户 ID 的数据。这是在引擎层面实现的行级安全。
- 对应
agents:read:team:- 关键属性
team: true: 类似地,这会自动限制查询范围在当前用户的团队内。
- 关键属性
第三层:角色与权限绑定 (roles.json)
这是将逻辑权限分配给具体用户的环节。
- Admin 角色: 拥有
system:admin,这是一个超级权限,通常在引擎内部处理逻辑中会绕过大部分检查。 - Guest 角色:
- 配置了
dsl:read:own,file:read:own等。 - 这意味着 Guest 用户虽然可以读取 DSL 或文件,但只能读取属于他们自己的(由
owner: true属性强制执行)。他们无法访问agents:read:all对应的全局数据接口。
- 配置了
3. 请求流转示例
假设一个用户(角色为 Guest)发起请求 GET /agent/agents/own:
- OpenAPI 守卫: 引擎检查
openapi.yao,验证 Request Header 中的 Bearer Token 是否有效(签名、过期时间)。 - Scope 匹配: 引擎查找
scopes/agent/agents.yml,发现该 URL 对应的 Scope 是agents:read:own。 - 权限检查: 引擎检查
roles.json中Guest角色是否包含agents:read:own。- 注意: 在你提供的
roles.json中,Guest 角色没有agents:read:own权限。 - 结果: 请求将被拒绝 (HTTP 403 Forbidden)。
- 注意: 在你提供的
- 修正: 如果你在
roles.json的 Guest 权限列表中添加了agents:read:own,请求将通过,并且引擎会自动附加WHERE owner_id = ?的查询条件。
4. 专家建议
作为 Yao Dev,我有几点建议:
- 利用
owner和team属性: 尽量在scopes定义中使用这两个属性,而不是在业务代码中手动写Where("user_id", id)。这样可以将安全逻辑从业务逻辑中解耦,由引擎统一保证。 - Scope 命名规范: 保持
资源:动作:范围(如agents:read:own) 的命名格式,这有助于在roles.json中清晰地管理成百上千个权限点。 - 开发环境 vs 生产环境:
scopes.yml中的endpoints部分允许了/dsl/*等接口。在生产环境中,建议移除或严格限制这些元数据管理接口的访问权限,除非你的应用是一个低代码开发平台。