资讯动态

用 Permify 为 Notion 类协作产品建模:从 DSL Schema 到自动化权限校验

发布时间:2026/9/17 19:55:36 来源:尧图企业网站定制
用 Permify 为 Notion 类协作产品建模从 DSL Schema 到自动化权限校验【免费下载链接】permifyAn open-source authorization as a service inspired by Google Zanzibar, designed to build and manage fine-grained and scalable authorization systems for any application. — Permify is now part of FusionAuth 项目地址: https://gitcode.com/GitHub_Trending/pe/permify本指南以 Permify 官方示例文档为核心完整演示如何为一款 Notion 风格的协作型应用含工作区、页面、数据库、块、评论、模板与集成构建细粒度授权模型并借助permify validate命令行工具在本地自动化验证权限逻辑。读完本文你将掌握 Permify DSL 中实体、关系、权限的建模方法、workspace#member这类跨实体关系继承的写法以及如何把权限用例写成可重复执行的 YAML 校验文件。场景概述为什么用 Permify 建模 Notion 类应用Notion 是一款典型的协作组织工具内容以页面page、数据库database、块block等形式存在并归属于某个工作区workspace不同用户承担 owner、admin、member、guest、bot 等不同角色同时内容对象自身还可以被单独授权给某个用户读写。这种组织级权限 对象级权限叠加的诉求正是 Google Zanzibar 风格授权系统的典型场景。Permify 通过一套声明式 DSL 来描述授权模型先用entity定义业务对象用relation定义对象之间的关系如页面的写者、工作区的成员再用permission把这些关系组合成可执行的动作如write、read。授权模型与业务数据完全分离权限判断由 Permify 的检查引擎在运行时完成。下文将基于官方示例 notion.mdx逐步给出完整 Schema、关系元组、权限推导分析和本地验证流程。第一步定义完整的授权模型 Schema以下是 Notion 授权模型的完整 Permify DSL 定义共包含 8 个实体entity user {} entity workspace { // The owner of the workspace relation owner user // Members of the workspace relation member user // Guests (users with read-only access) of the workspace relation guest user // Bots associated with the workspace relation bot user // Admin users who have permission to manage the workspace relation admin user // Define permissions for workspace actions permission create_page owner or member or admin permission invite_member owner or admin permission view_workspace owner or member or guest or bot permission manage_workspace owner or admin // Define permissions that can be inherited by child entities permission read member or guest or bot or admin permission write owner or admin } entity page { // The workspace associated with the page relation workspace workspace // The user who can write to the page relation writer user // The user(s) who can read the page (members of the workspace or guests) relation reader user workspace#member workspace#guest // Define permissions for page actions permission read reader or workspace.read permission write writer or workspace.write } entity database { // The workspace associated with the database relation workspace workspace // The user who can edit the database relation editor user // The user(s) who can view the database (members of the workspace or guests) relation viewer user workspace#member workspace#guest // Define permissions for database actions permission read viewer or workspace.read permission write editor or workspace.write permission create editor or workspace.write permission delete editor or workspace.write } entity block { // The page associated with the block relation page page // The database associated with the block relation database database // The user who can edit the block relation editor user // The user(s) who can comment on the block (readers of the parent object) relation commenter user page#reader // Define permissions for block actions permission read database.read or commenter permission write editor or database.write permission comment commenter } entity comment { // The block associated with the comment relation block block // The author of the comment relation author user // Define permissions for comment actions permission read block.read permission write author } entity template { // The workspace associated with the template relation workspace workspace // The user who creates the template relation creator user // The user(s) who can view the page (members of the workspace or guests) relation viewer user workspace#member workspace#guest // Define permissions for template actions permission read viewer or workspace.read permission write creator or workspace.write permission create creator or workspace.write permission delete creator or workspace.write } entity integration { // The workspace associated with the integration relation workspace workspace // The owner of the integration relation owner user // Define permissions for integration actions permission read workspace.read permission write owner or workspace.write }这套 Schema 与仓库中的示例文件 assets/example-shapes/notion.yaml 保持完全一致可以直接作为你编写权限用例 YAML 的蓝本。模型拆解实体与关系模型定义了user、workspace、page、database、block、comment、template、integration等实体并内置了 Admin、Bot、Guest、Member 等默认角色。逐一拆解如下user系统中的用户。它是空实体entity user {}只作为其他实体关系的 Subject 存在。workspace用户协作的工作区关联 owner所有者、member成员、guest只读访客、bot机器人和 admin管理员。owner 与 admin 拥有管理工作区的权限create_page、invite_member、view_workspace、manage_workspace定义了具体动作read与write两个权限可以被子实体继承。page工作区内的页面。每个页面关联一个工作区并拥有 writer写者和 reader读者read/write权限基于页面自身的 writer/reader 计算同时可继承所属工作区的权限workspace.read/workspace.write。database工作区内的数据库。每个数据库关联一个工作区并拥有 editor编辑者和 viewer查看者除read/write外还定义了create与delete。block页面或数据库内的内容块。每个块关联一个 page 或 database并拥有 editor 和 commenter评论者read/write可继承自所属数据库commenter 特指有权评论父对象的人。comment块上的评论。每条评论关联一个块并拥有 author作者read继承自所在块write仅授予作者本人。template工作区内的模板。每个模板关联一个工作区并拥有 creator创建者和 viewerread/write可继承自工作区另含create与delete。integration工作区内的集成应用。每个集成关联一个工作区并拥有 ownerread继承自工作区write授予 owner 或继承自工作区的写权限。理解reader user workspace#member workspace#guest这类多 Subject 关系注意page的reader关系写法relation reader user workspace#member workspace#guest它声明了读者可以是三类 Subject直接指定的user、该页面所属工作区的member集合、该页面所属工作区的guest集合。也就是说只要某个用户与页面所属工作区之间存在member或guest关系元组他就自动成为该页面的 reader。这正是 Permify 支持关系作为 Subject即嵌套关系的体现commenter user page#reader同理——块所在页面的 reader 集合成员即评论者。权限推导剖析以 page 的 read 权限为例模型为每个实体挂接了若干受权限限制的动作。这里以page的read权限为例展示权限是如何由关系和继承组合而成的entity workspace { // The owner of the workspace relation owner user // Members of the workspace relation member user // Guests (users with read-only access) of the workspace relation guest user // Bots associated with the workspace relation bot user // Admin users who have permission to manage the workspace relation admin user // Define permissions that can be inherited by child entities permission read member or guest or bot or admin .. } entity page { // The workspace associated with the page relation workspace workspace .. // The user(s) who can read the page (members of the workspace or guests) relation reader user workspace#member workspace#guest .. // Define permissions for page actions permission read reader or workspace.read .. }该权限决定谁能读取 Notion 中某页面的内容推导过程如下reader关系指定了那些是页面所属工作区的成员workspace#member或访客workspace#guest的用户以及被直接授予 reader 的用户workspace.read继承页面实体中继承了所属工作区的 read 权限即任何被授予了该工作区对象读权限的用户owner、member、guest、bot、admin 之一也能读这个页面综上凡是工作区成员/访客、被显式授予 reader、或对工作区本身拥有读权限的用户都可以读取页面内容。同样的模式贯穿全模型database.read viewer or workspace.read、block.read database.read or commenter、comment.read block.read、template.read viewer or workspace.read、integration.read workspace.read。可以看到权限沿workspace → page/database/template/integration → block → comment的链条逐级向下继承形成一棵天然的授权树这也是 Zanzibar 风格通过关系图递归推导权限的典型用法。第二步填充关系元组Relationship TuplesSchema 只是授权模型的骨架实际授权关系通过关系元组tuple表达。元组格式为entity:id#relationsubject例如workspace:engineering_team#owneruser:alice表示alice 是 engineering_team 工作区的 owner。基于上述 Schema创建如下示例关系来同时验证 Schema 与授权逻辑// Assign users to different workspaces: workspace:engineering_team#owneruser:alice workspace:engineering_team#memberuser:bob workspace:engineering_team#guestuser:charlie workspace:engineering_team#adminuser:alice workspace:sales_team#owneruser:david workspace:sales_team#memberuser:eve workspace:sales_team#guestuser:frank workspace:sales_team#adminuser:david // Connect pages, databases, and templates to workspaces: page:project_plan#workspaceworkspace:engineering_team page:product_spec#workspaceworkspace:engineering_team database:task_list#workspaceworkspace:engineering_team template:weekly_report#workspaceworkspace:sales_team database:customer_list#workspaceworkspace:sales_team template:marketing_campaign#workspaceworkspace:sales_team // Set permissions for pages, databases, and templates: page:project_plan#writeruser:frank page:project_plan#readeruser:bob database:task_list#editoruser:alice database:task_list#vieweruser:bob template:weekly_report#creatoruser:alice template:weekly_report#vieweruser:bob page:product_spec#writeruser:david page:product_spec#readeruser:eve database:customer_list#editoruser:david database:customer_list#vieweruser:eve template:marketing_campaign#creatoruser:david template:marketing_campaign#vieweruser:eve // Set relationships for blocks and comments: block:task_list_1#databasedatabase:task_list block:task_list_1#editoruser:alice block:task_list_1#commenteruser:bob block:task_list_2#databasedatabase:task_list block:task_list_2#editoruser:alice block:task_list_2#commenteruser:bob comment:task_list_1_comment_1#blockblock:task_list_1 comment:task_list_1_comment_1#authoruser:bob comment:task_list_1_comment_2#blockblock:task_list_1 comment:task_list_1_comment_2#authoruser:charlie comment:task_list_2_comment_1#blockblock:task_list_2 comment:task_list_2_comment_1#authoruser:bob comment:task_list_2_comment_2#blockblock:task_list_2 comment:task_list_2_comment_2#authoruser:charlie这套关系设计覆盖了四个层次工作区成员归属、内容对象页面/数据库/模板到工作区的挂接、内容对象级的直接授权以及块/评论级的最小粒度授权。第三步校验授权逻辑——两个典型检查场景有了 Schema 与关系元组就可以针对具体的权限检查请求推导结果验证授权逻辑是否符合预期。场景一user:alice能写database:task_list吗依据database实体的write权限定义entity database { // The workspace associated with the database relation workspace workspace // The user who can edit the database relation editor user .. permission write editor or workspace.write .. }能编辑database:task_list的用户只有两类task_list 数据库的 editor编辑者对该数据库所属的唯一工作区 engineering_teamdatabase:task_list#workspaceworkspace:engineering_team拥有write权限的用户。再看我们创建的关系元组user:alice并没有与database:task_list建立 editor 关系。但她在 engineering_team 工作区中同时是 owner 和 adminworkspace:engineering_team#owneruser:alice、workspace:engineering_team#adminuser:alice而工作区的write权限定义为entity workspace { // The owner of the workspace relation owner user .. // Admin users who have permission to manage the workspace relation admin user .. permission write owner or admin }由于write owner or adminalice 通过 owner/admin 身份持有工作区写权限而 engineering_team 又是 task_list 唯一关联的工作区。因此user:alice write database:task_list的检查结果应为true。场景二user:charlie能写page:product_spec吗依据page实体的write权限定义entity page { // The workspace associated with the page relation workspace workspace // The user who can write to the page relation writer user .. permission write writer or workspace.write }user:charlie在 engineering_team 工作区中的角色是 guestworkspace:engineering_team#guestuser:charlie而 engineering_team 是page:product_spec唯一关联的工作区。从工作区的write定义看entity workspace { // The owner of the workspace relation owner user // Admin users who have permission to manage the workspace relation admin user .. permission write owner or admin }guest 并不在owner or admin之列——我们在 Schema 中刻意没有给访客授予工作区写权限。同时 charlie 也没有与page:product_spec建立 writer 关系。因此user:charlie write page:product_spec的检查结果应为false。第四步把用例固化为 YAML 校验文件上面的人工推导只能验证两次无法持续回归。Permify 提供了声明式的校验文件格式把 Schema、关系元组和断言assertions写进同一个 YAML交给permify validate命令批量执行。将以下内容保存为校验文件例如notion-validation.yamlschema: - entity user {} entity workspace { // The owner of the workspace relation owner user // Members of the workspace relation member user // Guests (users with read-only access) of the workspace relation guest user // Bots associated with the workspace relation bot user // Admin users who have permission to manage the workspace relation admin user // Define permissions for workspace actions permission create_page owner or member or admin permission invite_member owner or admin permission view_workspace owner or member or guest or bot permission manage_workspace owner or admin // Define permissions that can be inherited by child entities permission read member or guest or bot or admin permission write owner or admin } entity page { // The workspace associated with the page relation workspace workspace // The user who can write to the page relation writer user // The user(s) who can read the page (members of the workspace or guests) relation reader user workspace#member workspace#guest // Define permissions for page actions permission read reader or workspace.read permission write writer or workspace.write } entity database { // The workspace associated with the database relation workspace workspace // The user who can edit the database relation editor user // The user(s) who can view the database (members of the workspace or guests) relation viewer user workspace#member workspace#guest // Define permissions for database actions permission read viewer or workspace.read permission write editor or workspace.write permission create editor or workspace.write permission delete editor or workspace.write } entity block { // The page associated with the block relation page page // The database associated with the block relation database database // The user who can edit the block relation editor user // The user(s) who can comment on the block (readers of the parent object) relation commenter user page#reader // Define permissions for block actions permission read database.read or commenter permission write editor or database.write permission comment commenter } entity comment { // The block associated with the comment relation block block // The author of the comment relation author user // Define permissions for comment actions permission read block.read permission write author } entity template { // The workspace associated with the template relation workspace workspace // The user who creates the template relation creator user // The user(s) who can view the page (members of the workspace or guests) relation viewer user workspace#member workspace#guest // Define permissions for template actions permission read viewer or workspace.read permission write creator or workspace.write permission create creator or workspace.write permission delete creator or workspace.write } entity integration { // The workspace associated with the integration relation workspace workspace // The owner of the integration relation owner user // Define permissions for integration actions permission read workspace.read permission write owner or workspace.write } relationships: - workspace:engineering_team#owneruser:alice - workspace:engineering_team#memberuser:bob - workspace:engineering_team#guestuser:charlie - workspace:engineering_team#adminuser:alice - workspace:sales_team#owneruser:david - workspace:sales_team#memberuser:eve - workspace:sales_team#guestuser:frank - workspace:sales_team#adminuser:david - page:project_plan#workspaceworkspace:engineering_team - page:product_spec#workspaceworkspace:engineering_team - database:task_list#workspaceworkspace:engineering_team - template:weekly_report#workspaceworkspace:sales_team - database:customer_list#workspaceworkspace:sales_team - template:marketing_campaign#workspaceworkspace:sales_team - page:project_plan#writeruser:frank - page:project_plan#readeruser:bob - database:task_list#editoruser:alice - database:task_list#vieweruser:bob - template:weekly_report#creatoruser:alice - template:weekly_report#vieweruser:bob - page:product_spec#writeruser:david - page:product_spec#readeruser:eve - database:customer_list#editoruser:david - database:customer_list#vieweruser:eve - template:marketing_campaign#creatoruser:david - template:marketing_campaign#vieweruser:eve - block:task_list_1#databasedatabase:task_list - block:task_list_1#editoruser:alice - block:task_list_1#commenteruser:bob - block:task_list_2#databasedatabase:task_list - block:task_list_2#editoruser:alice - block:task_list_2#commenteruser:bob - comment:task_list_1_comment_1#blockblock:task_list_1 - comment:task_list_1_comment_1#authoruser:bob - comment:task_list_1_comment_2#blockblock:task_list_1 - comment:task_list_1_comment_2#authoruser:charlie - comment:task_list_2_comment_1#blockblock:task_list_2 - comment:task_list_2_comment_1#authoruser:bob - comment:task_list_2_comment_2#blockblock:task_list_2 - comment:task_list_2_comment_2#authoruser:charlie scenarios: - name: scenario 1 description: test description checks: - entity: database:task_list subject: user:alice assertions: write: true - entity: page:product_spec subject: user:charlie assertions: write: false文件顶层由四个区块组成对应 pkg/development/file/shape.go 中Shape结构的定义schema授权模型的 DSL 文本Schema stringYAML 键schemarelationships关系元组字符串列表Relationships []stringYAML 键relationshipsattributes属性字符串列表Attributes []stringYAML 键attributes本例为空scenarios一个或多个测试场景Scenarios []Scenario每个场景内可包含checks权限检查断言、entity_filters实体查询断言与subject_filters主体查询断言。其中Check结构包含entity、subject与assertions权限名到期望布尔值的映射并可选depth与context字段。上例中的scenario 1就把前面两个人工推导的场景固化为机器可执行的断言database:task_list对user:alice的write期望为truepage:product_spec对user:charlie的write期望为false。第五步在本地运行验证克隆本项目并启动 Permify 实例make servemake serve等价于先构建再执行./permify serve见 Makefile 中的serve目标默认会启动本地 gRPC/HTTP 服务。接着将校验文件的路径传给permify validate命令开始测试permify validate {path of your schema validation file}例如permify validate ./notion-validation.yaml命令执行后终端会按schema 创建 → relationships 写入 → attributes 写入 → scenarios 检查的顺序输出进度每个元组与断言都有独立的 success/fail 提示最后以SUCCESS全部通过或FAILED存在断言不符收尾。validate 命令的底层执行链路permify validate的实现位于 pkg/cmd/validate.go其核心流程如下解码输入用url.Parse解析参数经 pkg/development/file/decoder.go 的NewDecoderFromURL按协议分派——本地文件走FileDecoderos.Open YAML 解析http/httpsURL 走HTTPDecoder因此校验文件既可以是本地路径也可以是远程 URL解析与编译 Schema先由schema.NewSchemaLoader()加载再用parser.NewParser(...).Parse()解析 DSL最后compiler.NewCompiler(true, sch).Compile()编译任何语法错误都会立即失败写入 Schema为每个实体语句生成一个SchemaDefinition统一使用租户t1与一个xid生成的版本号写入内存存储写入关系与属性逐条把relationships/attributes字符串解析为base.Tuple/base.Attribute对照实体定义执行validation.ValidateTuple/ValidateAttribute校验后写入存储执行场景断言对每个check调用dev.Container.Invoker.Check(...)发起权限检查默认Depth: 100来自Depth()函数最小值为 3将实际结果与assertions中期望值比对不一致即记录失败entity_filters与subject_filters则分别调用LookupEntity与LookupSubject期望值类型为实体 ID / 主体 ID 数组。值得注意的是validate命令运行在development.NewContainer()构建的开发容器中见 pkg/development/development.go。该容器通过工厂函数创建一个内存数据库并装配好 DataReader/DataWriter、SchemaReader/SchemaWriter、CheckEngine/LookupEngine 等组件与 DirectInvoker因此整个验证过程完全在本地内存中完成不依赖任何外部数据库非常适合 CI 场景下的授权回归测试。如果断言与预期不符例如某条检查实际为ALLOWED而期望DENIED命令会以fail: query - expected: DENIED actual: ALLOWED的形式指出具体是哪条subject permission entity组合出了问题便于精确定位模型漏洞。总结通过本示例可以看到用 Permify 为 Notion 这类协作型产品建模的完整链路是建模用entity/relation/permission三层结构描述对象、对象间关系与可执行动作将工作区角色 对象级授权统一进同一套关系图填充数据以entity:id#relationsubject元组表达真实授权关系包括跨实体关系如workspace#member与权限继承如workspace.read推导验证先人工推演关键权限路径再用scenarios断言固化为可重复执行的 YAML 校验文件自动化回归通过make servepermify validate file在本地内存环境中批量执行检查随时发现授权模型的逻辑错误。仓库中的 notion.yaml 已内置与本例一致的 Schema 与关系元组可作为其他建模场景Facebook 群组、Google Docs、Instagram 等见 docs/getting-started/examples的参考模板。关于如何安装、配置并接入 Permify 服务参见 Set Up Permify关于校验文件更多字段如entity_filters、subject_filters、depth、context的说明可结合 pkg/development/file/shape.go 的源码注释进一步查阅。【免费下载链接】permifyAn open-source authorization as a service inspired by Google Zanzibar, designed to build and manage fine-grained and scalable authorization systems for any application. — Permify is now part of FusionAuth 项目地址: https://gitcode.com/GitHub_Trending/pe/permify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价