OneUptime 权限参考(Permission Reference)完全指南:从 Permission Key 到角色与细粒度权限
2026/9/18 16:32:54 网站建设 项目流程

OneUptime 权限参考(Permission Reference)完全指南:从 Permission Key 到角色与细粒度权限

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

权限是 OneUptime 多租户项目中最核心的访问控制机制。本文以仓库内 App/FeatureSet/Docs/Content/en/permissions/reference.md 为主体,逐层拆解这份"权限参考"页面:它由什么生成、角色(Roles)与细粒度权限(Granular permissions)如何组织、Permission Key在 API / CLI / Terraform provider 中如何使用,以及背后的源码实现与完整性保障。读完本文,你将掌握按产品领域速查权限、为团队与 API Key 精确授权、以及理解"页面永不与产品漂移"这一机制的全部原理。

这份参考页从哪来:请求时从源码动态生成

reference.md本身并不是一份手写的权限清单。它的开头明确说明:

This page is generated from the OneUptime source at request time — the same list the dashboard, the API and the Terraform provider use. It cannot drift from the product, and it reflects the version you are running.

这意味着你看到的每一张权限表格,都是在页面被请求的那一刻,从正在运行的版本源码中实时渲染出来的。因此它天然具备两个特性:

  • 单一事实源(Single Source of Truth):Dashboard 的权限选择器、API 的鉴权逻辑、Terraform provider 的权限校验,全部读取同一份列表,任何一处新增权限都会同步出现在所有入口;
  • 永不漂移:不存在"文档写了一套、产品跑另一套"的陈旧问题。

占位符机制:页面模板如何被填充

reference.md正文中嵌入了若干形如{{PERMISSION_XXX}}的占位符,例如:

  • {{PERMISSION_ROLE_COUNT}}—— 角色总数
  • {{PERMISSION_ROLE_TABLES}}—— 角色表格
  • {{PERMISSION_TOTAL_COUNT}}—— 细粒度权限总数
  • {{PERMISSION_GROUP_COUNT}}—— 细粒度权限组总数
  • {{PERMISSION_GRANULAR_TABLES}}—— 细粒度权限表格

这些占位符由 App/FeatureSet/Docs/Utils/Placeholders.ts 中的DocsPlaceholders.render()在服务端渲染时统一替换。注意替换是白名单式的(allow-listed),并非对{{...}}的全局扫描——因为文档中合法地存在{{timestamp}}{{variable}}这类作为内容本身的双花括号语法(例如网站监控与工作流文档),它们必须原样保留。每个占位符的替换同样只针对包含该 token 的页面执行。

在 Placeholders.ts 中可以看到,替换时还会根据当前请求的语言(lang)选择表格"外壳"的翻译文本(列头、Yes/No),而权限标题与描述本身始终为英文,与 Dashboard 界面显示的字符串完全一致——这正是为了"读者对照屏幕时看到同一串文字"。

为什么不在构建期生成

按语言生成的角色表格与细粒度表格(后者约 1200 行)会被 PermissionsTable.ts 以Map<string, string>缓存到内存中,每个语言只构建一次,避免每次请求都重新遍历整个权限目录。从源码注释可以看到:细粒度表格约 1200 行,说明该页面实际承载的信息量远超模板本身的几行文字。

角色(Roles):Admin / Member / Viewer 三级打包

reference.md的 Roles 一节说明:角色将一个完整的产品领域打包为Admin、Member、Viewer三个层级,这正是 Dashboard 中给团队添加权限时Role选择器提供的选项。

结合 permissions/index.md 的模型定义,三级的语义是:

级别含义
Admin该领域的完全控制权,包括配置项(严重级别、状态、模板等)
Member日常操作:可创建、编辑、删除资源,但不能重新配置该领域
Viewer只读

典型角色如MonitorAdminIncidentMemberStatusPageViewerindex.md还给出一个重要建议:绝大多数场景优先使用角色而非细粒度权限——因为 OneUptime 新增功能时,新表会挂到既有角色上,而不是要求你逐个补发权限。

Scope 列:All, Owned or Labels vs Project-wide only

角色表格中有Scope(作用域)列,它回答"这个授权能管到多宽":

  • All, Owned or Labels:授予时可被收窄。可选的三种作用域(来自index.md):
    • All resources in the project(默认):作用于项目内所有匹配资源;
    • Owned by this team or its members:仅作用于该团队或其成员被列为所有者的资源;
    • Restrict by labels (advanced):仅作用于携带至少一个所选标签的资源。
  • Project-wide only:角色始终作用于整个项目,无法收窄。

作用域豁免角色:为什么有些角色不能收窄

在 Common/Types/Permission.ts 的PermissionHelper.isScopeApplicable()中,可以看到哪些角色被判定为"不适用作用域":

public static isScopeApplicable(permission: Permission): boolean { return ( permission !== Permission.ProjectOwner && permission !== Permission.ProjectAdmin && permission !== Permission.SettingsAdmin && permission !== Permission.SettingsMember && permission !== Permission.SettingsViewer && permission !== Permission.BillingAdmin && permission !== Permission.BillingMember && permission !== Permission.BillingViewer ); }

这些角色(ProjectOwnerProjectAdminSettings*Billing*)是无条件项目级授权,收窄会产生无法理解的语义——"Settings Admin,但只对我拥有的设置生效"没有意义,因为设置不是可拥有的资源。index.md中同样以"Billing Admin, but only for the billing I own"为例说明了这一点。对应的豁免角色清单由 PermissionsTable.ts 中的getScopeExemptRolesMarkdown()生成,供index.md中的{{PERMISSION_SCOPE_EXEMPT_ROLES}}占位符使用。

实现细节上:UI 会为这些角色隐藏作用域选择器;运行时过滤器也会将"误加的 Owned 作用域行"按更宽的授权处理,避免意外收窄访问(见 Permission.ts 中getNonAccessControlPermissions()的注释说明)。

细粒度权限(Granular permissions):按组组织的单个能力

reference.md的 Granular permissions 一节说明:细粒度权限是可单独授予的单个能力(如CreateProjectMonitorReadProjectIncident),按组(group)组织,来自Granular选择器,也是分配给API Key的权限类型。

权限组一览

在 Common/Types/Permission.ts 中定义了PermissionGroup枚举,即所有权限归属的 21 个组:

ProjectIncidentAlertMonitorSLOStatus PageScheduled MaintenanceOn-Call Duty PolicyTelemetryWorkflowRunbookAuto RemediationTeamBillingService CatalogSettingsAI AgentProbeNotification LogAudit LogSecurity

reference.md中的每个###小节对应一个组,组下再列出该组所有权限的表格——这也是页面右侧 "On This Page" 侧边栏的锚点,读者可以直接跳转到关心的组,而不必滚动上千行的总表(见 PermissionsTable.ts 的buildGroupedTables())。

Restrict by labels 列

细粒度表格中的Restrict by labels列表示:该权限的授予是否可以被限制到携带特定标签的资源上。在源码中对应PermissionProps.isAccessControlPermission布尔字段——为true的权限渲染为 Yes,否则为 No(见 PermissionsTable.ts)。

需要说明的是,这一列是每个权限的固有属性(legacy 标记),而实际的标签限制机制比它更灵活:index.mdPermissionHelper.getAccessControlPermissions()(Permission.ts)都指出,角色权限(如IncidentViewer)同样可以通过作用域选择 Labels + 勾选标签来实现标签限制,运行时过滤器依据的是scope+labelIds的组合,而不仅是该列标记。

Permission Key:API、CLI 与 Terraform provider 的通行值

reference.md专门强调:

ThePermission Keycolumn is the value to use with the API, the CLI and the Terraform provider. The titles are what you see in the dashboard.

即表格中反引号包裹的键值(如CreateProjectMonitorMonitorAdmin)才是程序化接口要使用的值,而标题(Title)仅用于界面展示。三种消费场景:

  • API:在创建 API Key 或调用接口时按键值授权。API Key 的授权与团队独立——键直接挂在 Key 上,不受团队成员身份影响(见 permissions/index.md);
  • CLI:命令行工具按键值管理权限;
  • Terraform provider:基础设施即代码中以键值声明权限。

index.md补充了与键值相关的两条重要规则:

  1. API Key 不支持 Owned 作用域——所有者解析的对象是"用户",而 Key 不是用户,因此需要显式授予 Key 所需的全部访问(index.md);
  2. Block 永远优先——Block 权限列表始终压过 Allow 列表;带标签的 Block 只移除携带该标签资源的权限(如"可以编辑监控,但 Production 标签的除外")。

底层实现:权限目录的生成与完整性保障

权限目录的构成

PermissionProps接口(Permission.ts)是每条权限的数据结构:

export interface PermissionProps { permission: Permission; // 枚举键,即 Permission Key description: string; // 描述 isAssignableToTenant: boolean; // 是否可授予项目 title: string; // 界面显示标题 isAccessControlPermission: boolean; // 是否可按标签限制 isRolePermission: boolean; // 是否为内置角色 group: PermissionGroup; // 所属权限组 }

PermissionHelper.getAllPermissionProps()(Permission.ts)返回完整目录,再由派生方法过滤出不同子集:

  • getTenantPermissionProps()—— 过滤isAssignableToTenant,即所有可授予项目的权限;
  • getRolePermissionProps()—— 在上一基础上过滤isRolePermission,得到内置角色列表;
  • 细粒度列表则是可授予权限中排除角色后的集合(见 PermissionsTable.ts 的getGranularPermissionProps())。

PermissionsTable.ts的文件头注释特别强调了"绝不手写副本"的原则:如果文档里维护一份手写的 markdown 权限清单,任何人新增一个权限后文档立刻失真——"一份关于权限却撒谎的文档比没有更糟"。

表格渲染细节:防破坏的单元格转义

Markdown 表格以|分隔、单元格须单行。若某条权限描述里恰好含有换行或竖线,会把整行拆成多余列或提前终结表格。为此 PermissionsTable.ts 中的toTableCell()做了三件事:

text .replace(/\r?\n/g, " ") // 换行折叠为空格 .replace(/\s+/g, " ") // 连续空白归一 .replace(/\|/g, "\\|") // 竖线转义 .trim();

同时,groupPermissions()首次出现顺序分组(而非PermissionGroup声明顺序),以匹配 Dashboard 选择器的分组顺序,保证文档与 UI 的序列一致(PermissionsTable.ts)。

完整性测试:防重复的"绊线"

权限目录长期存在两类静默缺陷:两个枚举成员共用同一字符串值(导致"授予其一即授予其二"、所有者作用域被意外放大),以及同一权限的PermissionProps被列出两次(导致 Granular 选择器出现重复项)。这两类问题 TypeScript 编译不会报错,因此 Common/Tests/Types/Permission.test.ts 提供了四组"目录完整性"测试作为绊线:

  • 枚举成员之间无重复字符串值
  • getAllPermissionProps()无重复条目
  • 每条 props 都能通过getTitle/getDescription无损往返(防止字典"后写覆盖"导致文档与界面文本不一致);
  • 标题含 "Template" 的条目其键名也必须含 "Template"(防止当年"模板所有者权限错挂到非模板成员"的 bug 复发)。

配套阅读:权限模型的完整上下文

reference.md是权限体系的"速查手册",其行为语义由 permissions/index.md 定义,二者应配合阅读:

  • 核心规则:用户从不直接持有权限,其访问权限等于所属所有团队权限的并集;ProjectOwner覆盖计费与删除项目,ProjectAdmin覆盖除计费外的一切;
  • 默认团队:每个新项目自带不可删除、不可改名的OwnersProjectOwner)与AdminProjectAdmin)团队,以及可自由修改的MembersProjectMember)团队——这是防止项目把自己锁在门外的设计;
  • 请求判定流程:依次为"收集团队权限行 → 先查 Block → 查 Allow → 应用 Owned/Labels 作用域收窄 → 应用标签 Block",解析结果按用户+项目缓存,权限变更后需刷新(index.md)。

index.md还给出了可直接落地的四种配置"配方":只读观察团队(加Viewer或按领域的*Viewer)、自管服务的值班团队(MonitorAdmin/IncidentMember/OnCallMember配 Owned 作用域 + 设为资源所有者)、隔离生产环境的承包商(All 作用域 + 对敏感能力加Production标签的 Block)、仅上报部署的 CI 流水线(API Key 只授必需细粒度权限)。这些配方与reference.md中的角色、细粒度权限一一对应,是验证"该授予哪个 Key"最直接的实战参考。

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询