Skip to content

进一步的理解yao 框架中的openapi权限 角色配置

基于https://github.com/YaoApp/yao-dev-appopenapi 目录下的配置文件,详细解析 Yao 框架的权限与角色配置逻辑:

1. 核心架构:三层权限模型

Yao 的权限系统可以看作是一个漏斗模型,请求需要依次通过以下三层验证:

  1. 认证层 (Authentication): 由 openapi.yao 定义,决定“你是谁”。
  2. 范围层 (Scopes): 由 scopes/*.yml 定义,决定“特定的 API 端点对应什么权限标识”。
  3. 角色层 (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: 这里可以进行粗粒度的控制(如直接 allowdeny),适用于不需要复杂权限判断的内部接口。
  • 细粒度资源范围 (如 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

  1. OpenAPI 守卫: 引擎检查 openapi.yao,验证 Request Header 中的 Bearer Token 是否有效(签名、过期时间)。
  2. Scope 匹配: 引擎查找 scopes/agent/agents.yml,发现该 URL 对应的 Scope 是 agents:read:own
  3. 权限检查: 引擎检查 roles.jsonGuest 角色是否包含 agents:read:own
    • 注意: 在你提供的 roles.json 中,Guest 角色没有 agents:read:own 权限。
    • 结果: 请求将被拒绝 (HTTP 403 Forbidden)。
  4. 修正: 如果你在 roles.json 的 Guest 权限列表中添加了 agents:read:own,请求将通过,并且引擎会自动附加 WHERE owner_id = ? 的查询条件。

4. 专家建议

作为 Yao Dev,我有几点建议:

  1. 利用 ownerteam 属性: 尽量在 scopes 定义中使用这两个属性,而不是在业务代码中手动写 Where("user_id", id)。这样可以将安全逻辑从业务逻辑中解耦,由引擎统一保证。
  2. Scope 命名规范: 保持 资源:动作:范围 (如 agents:read:own) 的命名格式,这有助于在 roles.json 中清晰地管理成百上千个权限点。
  3. 开发环境 vs 生产环境: scopes.yml 中的 endpoints 部分允许了 /dsl/* 等接口。在生产环境中,建议移除或严格限制这些元数据管理接口的访问权限,除非你的应用是一个低代码开发平台。