关于 vtex-io-rbac
面向 VTEX IO 应用开发者的访问控制技能,说明如何根据调用方选择基于角色或资源的策略。内容涵盖 REST、GraphQL、VRN、授权配置及常见 403 问题排查。
主要功能
- 01区分基于角色与基于资源的策略
- 02配置 REST 路由访问策略
- 03使用 GraphQL @auth 指令授权
- 04编写用于标识资源和调用方的 VRN
- 05排查策略配置导致的 403 错误
适用场景
- 01限制 REST 端点仅由指定应用调用
- 02允许用户或 API 密钥访问私有路由
- 03为 GraphQL 查询和变更添加授权
- 04检查通配符策略引发的访问拒绝
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vtex/ skills --skill vtex-io-rbac安装后在 Claude Code 中输入/vtex-io-rbac确认已加载。
详细介绍
VTEX IO 访问控制(RBAC)
适用场景
当你需要控制谁可以访问 VTEX IO 应用的路由和资源时,使用此技能:
- 在基于角色(
policies.json)和基于资源(service.json策略)的访问控制之间做出选择 - 保护 REST 端点,确保只有特定应用、用户或 API 密钥可以调用
- 使用
@auth指令设置 GraphQL 授权 - 了解用于声明主体的 VRN(VTEX Resource Name)语法
- 排查由缺少或配置错误的策略导致的 403 Forbidden 错误
请勿在以下情况使用此技能:
- 常规服务架构(使用
vtex-io-service-apps) - PCI 合规性和支付安全(使用
payment-pci-security) - 路由前缀和 CDN 行为(使用
vtex-io-service-paths-and-cdn)
决策规则
基于角色的策略与基于资源的策略
基于角色(policies.json) | 基于资源(service.json 策略) | |
|---|---|---|
| 谁可以调用? | 仅限其他 IO 应用(代表自身或代表其他应用) | 应用、用户和集成(API 密钥) |
| API 类型 | GraphQL 和 REST | 仅 REST |
| 调用方如何获得访问权限 | 必须在其 manifest.json 中声明所需策略 | 无需声明策略;使用身份验证令牌调用即可 |
| 配置位置 | 应用根目录中的 policies.json | service.json 中路由定义内的 policies 数组 |
| 适用场景 | 暴露 GraphQL 端点;仅面向应用间调用者暴露 REST 端点 | 控制用户、API 密钥或特定应用对 REST 端点的访问 |
选择合适的方法
- GraphQL 端点 → 使用基于角色的策略(
policies.json),和/或在架构中使用@auth指令进行用户级授权。 - 仅由其他 IO 应用调用的 REST 端点 → 使用基于角色的策略(
policies.json)。消费方应用必须在其manifest.json中声明该策略。 - 由用户或 API 密钥调用的 REST 端点 → 在
service.json中使用基于资源的策略。将路由设为"public": false并定义主体。 - 公共 REST 端点(无需身份验证) → 在
service.json中设置"public": true。无需策略,但请注意,这意味着任何人都可以调用。
VRN 语法
VRN(VTEX Resource Name)用于标识资源和主体:
vrn:{service}:{region}:{account}:{workspace}:{path}
- 应用:
vrn:apps:*:*:*:app/{vendor}.{app-name}@{version} - 用户:
vrn:vtex.vtex-id:*:*:*:user/{email} - API 密钥:
vrn:vtex.vtex-id:*:*:*:user/vtexappkey-{account}-{hash} - 通配符:
*匹配段中的任意值。app/*匹配所有应用。user/*@gmail.com匹配所有 Gmail 用户。
硬性约束
约束:用户或 API 密钥需要访问时,使用基于资源的策略
基于角色的策略仅适用于应用到应用的通信。如果用户(管理员或店面用户)或集成(API 密钥)需要调用你的端点,必须在 service.json 中使用基于资源的策略,并将路由设置为 "public": false。
原因 — 如果为用户或 API 密钥调用的路由配置基于角色的策略,这些调用者会收到 403 Forbidden,因为基于角色的策略不会评估用户或集成令牌。
检测方式 — 应允许管理员用户或外部集成调用的私有路由,仅配置了 policies.json,而 service.json 中没有 policies 数组。
正确做法 — 在 service.json 中为用户/集成访问配置基于资源的策略。
{
"routes": {
"orders": {
"path": "/_v/private/my-app/orders",
"public": false,
"policies": [
{
"effect": "allow",
"actions": ["GET", "POST"],
"principals": [
"vrn:vtex.vtex-id:*:*:*:user/*@mycompany.com",
"vrn:apps:*:*:*:app/partner.integration-app@*"
]
}
]
}
}
}
错误做法 — 用户需要调用的路由仅配置了 policies.json。
// policies.json — this only covers app-to-app, not users
[
{
"name": "access-orders",
"statements": [
{
"effect": "allow",
"actions": ["GET"],
"resources": ["vrn:my-app:*:*:*:/_v/private/my-app/orders"]
}
]
}
]
// Users calling this route still get 403
约束:拒绝策略优先于允许策略
当基于资源的策略中的 allow 和 deny 规则存在重叠主体时,始终以 deny 为准。请谨慎处理与特定拒绝规则相交的允许规则中的通配符。
原因 — app/* 的宽泛 allow 与针对 app/vendor.bad-app@* 的特定 deny 组合时,会正确阻止 bad-app。但反过来,宽泛的 deny 配合特定的 allow 会阻止所有内容,包括你想允许的内容。
检测方式 — 同一路由存在多个效果冲突且主体重叠的策略条目。
正确做法 — 广泛允许,具体拒绝。
{
"policies": [
{
"effect": "allow",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/*"]
},
{
"effect": "deny",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/untrusted.app@*"]
}
]
}
错误做法 — 广泛拒绝,再尝试具体允许(允许规则会被覆盖)。
{
"policies": [
{
"effect": "deny",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/*"]
},
{
"effect": "allow",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/trusted.app@*"]
}
]
}
推荐模式
基于角色的策略(policies.json)
[
{
"name": "resolve-graphql",
"description": "Allows apps to resolve GraphQL requests",
"statements": [
{
"effect": "allow",
"actions": ["POST"],
"resources": [
"vrn:vtex.store-graphql:{{region}}:{{account}}:{{workspace}}:/_v/graphql"
]
}
]
}
]
调用方应用在其 manifest.json 中声明策略:
{
"policies": [
{
"name": "resolve-graphql"
}
]
}
混合访问的基于资源的策略
{
"routes": {
"webhook": {
"path": "/_v/private/my-app/webhook",
"public": false,
"policies": [
{
"effect": "allow",
"actions": ["POST"],
"principals": [
"vrn:apps:*:*:*:app/vtex.orders-broadcast@*",
"vrn:vtex.vtex-id:*:*:*:user/vtexappkey-myaccount-*"
]
}
]
}
}
}
GraphQL @auth 指令
对于 GraphQL 端点,使用 @auth 指令进行用户级授权:
type Query {
orders: [Order] @auth(productCode: "10", resourceCode: "list-orders")
adminSettings: Settings
@auth(productCode: "10", resourceCode: "admin-settings")
}
type Mutation {
updateSettings(input: SettingsInput!): Settings
@auth(productCode: "10", resourceCode: "admin-settings")
}
@auth 指令会检查调用方在指定 productCode 和 resourceCode 下的 License Manager 角色。
常见故障模式
- 基于角色的路由对用户返回 403 — 路由仅配置了
policies.json;用户和 API 密钥会收到 403,因为基于角色的策略不适用于他们。 public: true范围过宽 — 路由应为私有,却被设置为公开。任何人都可以在未进行身份验证的情况下调用它。- 调用方清单中缺少策略 — 应用尝试调用受基于角色的策略保护的路由,却未在其
manifest.json中声明该策略,因此会返回 403。 - VRN 拼写错误 — VRN 中的供应商、应用名称或主体格式拼写错误。匹配会静默失败,导致返回 403。
deny中使用通配符 — 使用app/*的宽泛拒绝规则会阻止所有应用,包括受信任的应用。拒绝规则优先。- GraphQL mutation 缺少
@auth— 修改数据的 mutation 无需角色检查即可访问。
审查清单
- 访问控制类型(基于角色还是基于资源)是否适用于调用方(应用还是用户/集成)?
- 私有路由是否设置为
"public": false并配置了适当的策略? - VRN 的主体类型(应用、用户、API 密钥)格式是否正确?
- 调用方应用是否在其
manifest.json中声明了所需的基于角色的策略? - 是否谨慎使用拒绝规则(它们会对主体重叠的允许规则产生覆盖)?
- GraphQL mutation 是否配置了
@auth指令,且productCode和resourceCode正确? - 通配符主体的范围是否尽可能小?
相关技能
- vtex-io-service-apps — 服务类、客户端和路由配置
- vtex-io-app-contract — 清单、构建器和策略声明
- vtex-io-graphql-api — GraphQL schema 和
@auth指令详情 - vtex-io-service-paths-and-cdn — 路由前缀模式
参考资料
- 控制对应用资源的访问 — 基于角色和资源的策略、VRN 语法、主体类型
- 使用 Auth Token 进行应用身份验证 — 用于应用间和用户与应用间通信的 Auth Token 类型
- IO 应用中的 GraphQL 授权 — @auth 指令的用法
- VTEX IO VRN — VTEX Resource Name 格式和示例