资讯动态

Frappe v8.7 用户权限模块解析:User Permission DocType 的字段、API 与底层实现

发布时间:2026/9/15 15:22:56 来源:尧图企业网站定制
Frappe v8.7 用户权限模块解析User Permission DocType 的字段、API 与底层实现【免费下载链接】frappeLow code web framework for real world applications, in Python and Javascript项目地址: https://gitcode.com/GitHub_Trending/fr/frappe导读本文基于 Frappe 框架变更日志 frappe/change_log/v8/v8_7_0.md 中 v8.7.0 的核心更新——User Permission is now a DocType——展开讲解。该版本把用户权限从原先零散的管理入口收敛为一个独立的文档类型DocType并提供了全新的录入界面用于替代原有的 Role / User Permission 管理器。读完本文你将掌握 User Permission 文档的每个字段含义、前端录入与批量操作的完整流程、后端frappe.permissions的鉴权链路以及嵌套树、默认值、按 DocType 适用范围等高级用法能够直接在自己的 Frappe 站点上配置并验证基于文档级的行级数据隔离。一、v8.7 更新背景为什么把 User Permission 变成 DocType1.1 变更日志原文v8.7.0 的变更日志frappe/change_log/v8/v8_7_0.md全文如下User PermissionsUser Permission is now a DocType, a new UX for the existing Role and User Permission managers to make it easy to enter permissions. For more details please check User Permissions从源码结构看这次变更的落地方式是在 Core 模块下新增User PermissionDocType 的完整四件套——元数据定义JSON、后端控制器Python、表单脚本与列表视图脚本JavaScript——让给某用户开放某文档的访问权这件事从硬编码逻辑变成可查询、可导入、可审计的普通数据记录。1.2 这一变更带来的能力提升将用户权限实体化成为 DocType后获得的能力包括可批量维护支持allow_import可通过 CSV 导入批量创建权限记录见 user_permission.json可审计追踪track_changes开启任何权限变更都有时间戳与操作者记录可编程操作后端暴露了add_user_permissions、clear_user_permissions等白名单 API可被前端对话框或脚本调用权限本身可被权限控制只有System Manager角色拥有该 DocType 的完整读写权限见 user_permission.json。二、User Permission DocType 字段全景User Permission 的完整字段定义位于 frappe/core/doctype/user_permission/user_permission.json。核心字段如下表字段名字段类型是否必填说明userLink (User)是被授予权限的用户建立了搜索索引用于快速按用户检索allowLink (DocType)是允许访问的文档类型DocType表单中过滤掉 Single 与 Table 类型for_valueDynamic Link是具体允许访问的文档记录动态链接到allow指定的 DocTypeis_defaultCheck否标记该记录为默认权限影响新建文档时默认值的选取apply_to_all_doctypesCheck否默认勾选是否将该权限应用到所有相关 DocTypeapplicable_forLink (DocType)条件必填仅当应用到所有 DocType未勾选时必填指定权限实际生效的 DocTypehide_descendantsCheck否默认隐藏对树形Nested SetDocType 生效勾选后隐藏指定节点的所有后代2.1 字段间的联动约束allow只能选择普通 DocType表单脚本通过set_query(allow, ...)过滤issingle: 0且istable: 0见 user_permission.jsapplicable_for的候选列表来自get_applicable_for_doctype_list白名单接口user_permission.py它基于get_linked_doctypes找出与allow所选 DocType 有关联的所有 DocType再补充当前 DocType 本身勾选应用到所有 DocType时会自动清空applicable_for并且前端将其改为必填/隐藏联动user_permission.jshide_descendants仅在allow属于 Nested Set树形DocType 时显示判断依据是frappe.boot.nested_set_doctypesuser_permission.js。三、数据校验与缓存失效后端控制器的核心逻辑User Permission 的后端控制器在 frappe/core/doctype/user_permission/user_permission.py 中UserPermission类继承Document。3.1 保存时的双重校验validate保存含插入任何 User Permission 记录时都会执行两步校验重复记录校验validate_user_permission按user allow for_value applicable_for apply_to_all_doctypes组合查重命中则抛出DuplicateEntryErroruser_permission.py默认值重叠校验validate_default_permission若本记录勾选了is_default则检查同一用户、同一allow下是否已存在其他默认记录含应用到所有 DocType的记录存在则拒绝保存防止同一 DocType 出现两个默认值user_permission.py。3.2 变更后的缓存与实时同步on_update与on_trash中执行两件事user_permission.pyfrappe.cache.hdel(user_permissions, self.user)删除该用户在 Redis 中的权限缓存frappe.publish_realtime(update_user_permissions, userself.user, after_commitTrue)事务提交后通过 WebSocket 通知前端刷新该用户的权限状态保证多端登录下权限即时生效。3.3 权限读取与缓存构建get_user_permissions(user)user_permission.py是整条鉴权链的数据源头Administrator与Guest直接返回空字典不受用户权限约束优先从frappe.cache.hget(user_permissions, user)读取缓存未命中时遍历该用户的所有 User Permission 记录按allow分组聚合每条记录以{doc, applicable_for, is_default, hide_descendants}形式存入树形扩展若allow对应的元数据是 Nested Setmeta.is_nested_set()且未勾选hide_descendants会通过frappe.db.get_descendants把该节点的所有后代文档也加入允许列表结果写入frappe.cache.hset(user_permissions, user, out)供后续请求复用捕获SQLError中的表不存在异常以兼容 patch 升级场景。另外send_user_permissions(bootinfo)会在登录启动阶段把当前用户权限注入bootinfo.user[user_permissions]前端据此渲染get_current_user_permissions则以白名单接口形式返回当前登录用户的权限user_permission.py。四、鉴权引擎has_user_permission 如何消费 User Permission用户权限最终在 frappe/permissions.py 的has_user_permission(doc, user, ...)frappe/permissions.py中生效其判断分两步STEP 1 —— 检查文档自身若user_permissions中存在该文档的 DocType则比对文档 name 是否在允许列表中树形 DocType 创建场景则沿父节点向上回溯匹配并参考各节点的hide_descendants标记。STEP 2 —— 检查所有 Link 字段遍历文档含子表行的全部 Link 字段若字段指向的 DocType 存在用户权限规则则校验字段值是否在允许集合内空值在非严格模式下放行。被拒绝时会给出精确报错信息例如You are not allowed to access this {0} record because it is linked to {1} {2} in row {3}, field {4}frappe/permissions.py方便定位是哪个字段、哪一行引发拦截。4.1 严格模式开关鉴权行为受系统设置apply_strict_user_permissions控制字段定义于 frappe/core/doctype/system_settings/system_settings.json开启后Link 字段为空值也会被校验新建未保存文档在read/write操作下同样适用关闭默认时空 Link 字段跳过校验Single 文档类型永远不应用严格模式因为其内含大量空 Link 字段。4.2 默认值辅助get_permitted_documents(doctype)与filter_allowed_docs_for_doctypefrappe/permissions.py会把is_default标记的记录排在允许列表最前供新建文档时自动填入默认值使用——这正是test_default_user_permission所验证的行为给某用户配置了 Blog Category 的默认权限后新建 Blog Post 时其分类字段会自动取默认值。五、前端体验表单、批量对话框与快捷操作5.1 表单视图frappe/core/doctype/user_permission/user_permission.js 在表单页提供allow/applicable_for的动态查询过滤见 2.1一个自定义按钮View Permitted Documents点击后跳转到Permitted Documents For User报表并带入当前用户作为过滤条件user_permission.js。5.2 列表视图的Add / Update对话框frappe/core/doctype/user_permission/user_permission_list.js 在列表页注入了两个高效入口Add / Update添加/更新弹出对话框依次选择用户 → DocType → 具体文档再选择是否应用到所有 DocType、是否设为默认、是否隐藏后代以及取消全部应用后勾选具体的 Applicable DocTypes 多选列表。提交时调用后端白名单方法frappe.core.doctype.user_permission.user_permission.add_user_permissions返回1表示创建/更新成功0表示无变化。该接口内部自动处理三种场景的原子切换user_permission.py从应用到所有切换到部分 DocType先删除原有的全部应用记录再为选中的每个 DocType 分别创建applicable_for记录从部分 DocType切换到全部应用删除所有applicable_for记录创建一条apply_to_all_doctypes1的记录保持不变直接返回 0。Bulk Delete批量删除按用户 DocType两个条件一键清空该用户在该 DocType 上的全部权限调用clear_user_permissions接口并反馈删除条数user_permission_list.js删除后frappe.clear_cache()确保立即生效。六、编程式用法通过 API 维护权限除界面操作外可以在代码或 Console 中直接调用以下白名单接口均要求System Manager角色接口作用add_user_permissions(data)传入{user, doctype, docname, is_default, apply_to_all_doctypes, applicable_doctypes, hide_descendants}按第四节所述逻辑创建/更新权限user_permission.pyclear_user_permissions(user, for_doctype)删除指定用户在某 DocType 上的全部权限返回删除条数user_permission.pycheck_applicable_doc_perm(user, doctype, docname)查询某权限目前作用于哪些 DocTypeuser_permission.pyget_current_user_permissions()获取当前登录用户的全部权限user_permission.pyPython 侧通用辅助函数非白名单from frappe.core.doctype.user_permission.user_permission import ( get_user_permissions, # 获取指定用户默认当前用户的权限字典 user_permission_exists, # 判断相似权限是否已存在 get_permitted_documents, # 获取当前用户在指定 DocType 上被允许的文档列表 ) from frappe.permissions import has_user_permission # 判断用户是否可访问某文档权限结构示例get_user_permissions的返回值按 DocType 分组{ Customer: [ {doc: CUST-00001, applicable_for: Sales Order, is_default: 0, hide_descendants: 0}, {doc: CUST-00002, applicable_for: None, is_default: 1, hide_descendants: 0}, ] }七、测试用例验证行为与边界User Permission 的功能由 frappe/core/doctype/user_permission/test_user_permission.py 覆盖主要场景包括默认值唯一性test_default_user_permission_validation验证同一用户同一 DocType 下重复创建默认权限会抛出ValidationError新建文档取默认值test_default_user_permission验证配置默认权限后用户新建文档时关联字段自动填入默认值全部应用 ↔ 部分应用的切换test_for_apply_to_all_on_update_from_apply_all、test_for_applicable_on_update_from_apply_to_all等用例验证两种模式互转时记录的增删行为部分转全部会删除所有applicable_for记录全部转部分会删除apply_to_all_doctypes记录嵌套树后代可见性test_user_perm_for_nested_doctype在树形 DocTypePerson上验证给父节点授权后子节点默认可见has_user_permission返回 True勾选hide_descendants后子节点立即不可见权限作用域隔离test_user_perm_on_new_doc_with_field_default验证在无关 DocType 上创建的权限不会影响其他 DocType 新建文档的默认值行为。这些用例同时验证了has_user_permission位于 frappe/permissions.py与get_user_permissions的完整链路是理解本文所述机制的可靠参照。八、实践建议与注意事项先角色权限、后用户权限User Permission 属于行级记录级数据过滤它叠加在角色权限之上用户仍需通过角色获得对应 DocType 的读/写权限User Permission 负责进一步缩小可见范围合理使用应用到所有 DocType默认勾选意味着该权限会作用于所有关联 DocType若只想限定某个业务场景如仅对 Sales Order 生效务必取消勾选并指定applicable_for善用默认权限为常用文档设置is_default可减少新单据录入时的选择成本但注意每个用户在每个 DocType 上只能有一个默认记录树形 DocType 的可见性对树形数据如账户科目、部门授权父节点会默认包含后代如需隐藏后代请勾选hide_descendants权限变更即时生效修改权限后缓存与前端实时状态会自动刷新无需重启服务但若通过 CSV 导入权限导入完成后建议手动执行一次frappe.clear_cache()。小结从 v8.7.0 起User Permission 在 Frappe 框架中正式成为一等公民 DocType其字段设计user/allow/for_value/is_default/apply_to_all_doctypes/applicable_for/hide_descendants与配套的缓存、校验、实时同步机制共同构成了框架级的行级数据权限方案。本文围绕变更日志这一入口结合 user_permission.json、user_permission.py、permissions.py 及对应测试文件完整还原了该特性的字段含义、前端操作、后端 API 与鉴权原理可作为在 Frappe 站点上配置与二次开发用户权限的实战参考。【免费下载链接】frappeLow code web framework for real world applications, in Python and Javascript项目地址: https://gitcode.com/GitHub_Trending/fr/frappe创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

免费获取报价