跳至内容

第10章 配套实验模块与练习

本教材附带一个可安装的最小模块:

myaddons/odoo_permission_lab/
├── __manifest__.py
├── models/lab_document.py
├── security/permission_lab_groups.xml
├── security/ir.model.access.csv
├── security/permission_lab_rules.xml
├── views/lab_document_views.xml
└── tests/test_permission_lab.py

它不是生产权限模块,而是用最少代码把本文公式变成可重复实验。只应安装在专用学习数据库。

10.1 安装与测试

请使用你当前环境中真实的配置文件、addons path 和专用学习库名:

./odoo-bin -c <学习环境配置> -d <专用学习库> \
  --addons-path=myaddons,addons -i odoo_permission_lab --stop-after-init

在全新专用测试库中运行模块测试,要用 -i 安装:

./odoo-bin -c <学习环境配置> -d <专用测试库> \
  --addons-path=myaddons,addons -i odoo_permission_lab \
  --test-enable --test-tags /odoo_permission_lab --stop-after-init

只有模块已经安装在该专用库中时,才把 -i 换成 -u 做升级测试。不要把 -i-u 或测试命令直接指向生产数据库。若现有配置已经声明完整 addons path,应以现有配置为准。

10.2 模型设计

实验模型为 permission.lab.document

字段 用途 要观察的权限点
name 标题 普通字段
owner_id 负责人 本人范围规则
member_ids 共享成员 OR 条件
company_id 公司 全局规则
related_document_id 关联文档 check_company=True 关联一致性
amount 金额 普通可写字段
state 工作流状态 UI readonly + 服务端专用 action
confidential_note 经理备注 Python 字段 groups=

模型设置 _check_company_auto = True,并在 related_document_id 上设置 check_company=True,用于把关联一致性与记录可见性分开实验。状态不能通过普通 write() 改,只能通过 action_submit()action_approve();后者显式检查组、记录 write、状态和“不能自批”。

10.3 组与 ACL

Permission Lab / User
  implied -> base.group_user

Permission Lab / Manager
  implied -> Permission Lab / User

ACL:

Read Write Create Unlink
User 1 1 1 0
Manager 1 1 1 1

经理继承用户组,因此两条 ACL 都适用,最终做并集。用户没有任何 unlink grant,所以即使某条记录规则匹配也不能删除。

10.4 三条规则如何组合

实验模块配置:

全局 Company:company_id in company_ids

组 User:owner_id = user.id OR member_ids 包含 user.id

组 Manager:TRUE

最终:

普通用户 = Company AND (OwnOrShared)
经理     = Company AND (OwnOrShared OR TRUE)
         = Company

经理可以看当前启用公司的全部实验文档,但经理的 TRUE 组规则不能突破全局公司规则。这是设计强制边界时最重要的组合模式之一。

User 规则对四种操作都生效,所以共享成员不仅能读,也能写整条记录,包括 owner_idmember_idscompany_id。这是为了集中演示宽规则和“写前检查”的故意设计,不是推荐的生产策略;真实模块通常应拆分 read 与 write/create 规则,并在 write() 中保护负责人、成员、公司等边界字段。

10.5 建议建立的测试用户

用户 用途
A Permission Lab / User 创建自己的文档
B Permission Lab / User 创建另一条文档并共享给 A
M Permission Lab / Manager 看全量、审批、访问经理字段
N 仅 Internal User 验证没有实验模型 ACL

准备记录:

记录 Owner Members Company
D1 A C1
D2 B C1
D3 B A C1
D4 B C2

在只启用 C1 时,预期 read:

用户 D1 D2 D3 D4
A 可见 不可见 可见 不可见
B 不可见 可见 可见 不可见
M 可见 可见 可见 不可见
N 无模型 read ACL

10.6 十个动手实验

实验 1:没有 ACL 时默认拒绝

让 N 直接 search 模型,观察 ACL AccessError。然后不要改规则,只给 N 加实验 User 组,确认 ACL grant 后才能进入规则层。

实验 2:ACL 做并集

临时创建一个只给 unlink 的额外组并授予 A,观察 A 的最终权限变成原 User ACL 加 unlink,而不是新组覆盖旧组。

实验 3:search 静默过滤与 browse 抛错

以 A 搜索 D2,结果应为空;再以 A browse(D2.id).read(['name']),观察显式访问错误。

实验 4:组规则 OR

给 A 加 Manager 组,A 同时匹配 User 和 Manager 规则。观察 Manager 的 TRUE 规则把 C1 内范围放宽到全部。

实验 5:全局规则不可被经理放宽

只启用 C1 时,以 M 搜索 D4。即使经理组规则为 TRUE,D4 仍被全局 Company 规则拒绝。

再把 C1 文档的 related_document_id 指向 D4,观察 _check_company_auto + check_company=True 即使在 sudo 下也拒绝跨公司关联。前一个实验回答“能否看到记录”,后一个回答“能否建立关联”,二者不能互相替代。

实验 6:perm_* 不是拒绝

复制 User 规则,取消 perm_write,然后停用原 User 规则。观察这条规则不再限制 write,而不是禁止 write。规则数据位于 noupdate="1" 区域,手工改动后普通模块升级不会可靠恢复原值;实验完成后应手工恢复并核对,最稳妥的做法是重建专用学习库。

实验 7:字段组

以 A 显式 read/write confidential_note,应抛 AccessError;以 M 操作应成功。再尝试 A 在 create payload 中传该字段,实验模型的 create 加固同样应拒绝。

实验 8:按钮隐藏不能保护方法

以 A 直接调用 action_approve(),即使不经过 UI 按钮,也会进入公开方法。确认服务端组校验拒绝 A。然后临时注释方法内组校验,仅依赖按钮 groups,观察为何会形成漏洞。

实验 9:write 规则检查旧状态

A 对自己的 D1 有 write。让 A 直接把 owner_id 改为 B;当前实验模型故意没有禁止负责人转移。写入可能成功,随后 D1 从 A 的 search 结果中消失。这正是“记录规则不是写后业务约束”的演示。

生产代码若不允许转移,应在 write 中限制 owner_id,而不是只依赖 own rule。

实验 10:职责分离

A 提交 D1,M 审批应成功。再让 M 创建、提交自己的文档并尝试自批,方法应拒绝。确认这是业务方法的规则,而不是 ACL 或 record rule 自动提供的能力。

10.7 实验与自动化测试的对应关系

实验 当前自动化覆盖 仍需手工观察
1 outsider 无 ACL 被拒绝 运行时加组及 cache 失效
2 User/Manager ACL 正向行为 临时额外 unlink grant 的并集
3 search 过滤、显式 read 抛错 错误提示的界面差异
4 Manager TRUE 规则放宽组规则范围 给现有 A 动态加组
5 全局公司规则、显式读取、非法 context 与跨公司关联 公司切换器中的交互
6 克隆库中改 perm_write 并重建库
7 read/write/create 字段限制 fields_get 和表单裁剪
8 直接方法调用和直接 state write 被拒绝 浏览器中按钮裁剪、真实 JSON-RPC
9 owner 写前规则实验 search 结果变化的界面观察
10 正常审批、自批/重复审批拒绝、非草稿删除拒绝 错误展示与批量边界

测试模块主要验证服务端安全边界,不等于已经覆盖菜单、动作、视图裁剪和完整 HTTP 路由。学习时保留手工实验;生产模块还应补 HttpCase、浏览器流程、组撤销、缓存和性能回归。

10.8 延伸练习

完成基础实验后,可以逐项扩展,但每次只改一个变量:

  1. 将 User 的 read 范围设为本人或成员,write 范围改为仅本人。
  2. 增加“已提交记录普通用户只读”的策略,并分析组规则 OR 是否意外放宽。
  3. 增加明细行模型,分别保护主单和行。
  4. 增加报表动作,测试隐藏 Print 入口后能否直达 URL。
  5. 增加 portal 用户和 token controller,实践先非 sudo、后 token、再最小 sudo。
  6. 增加部门树 parent_path,比较 child_of 与预计算部门范围的 SQL。
  7. 给角色增加到期时间,验证只靠 cron 回收为什么存在时间窗口。
  8. 模拟 sudo 预取后 with_user(),写缓存回归测试。

老赵解读

实验模块的价值不在于展示一套标准答案,而在于把抽象规则变成可重复的观察。建议每次只改变一个变量:换用户、换公司、换记录状态或增减一条规则,然后同时观察界面、ORM 结果、异常和 SQL。最终把每个手工实验固化为自动化测试,学习成果才会变成可复用的工程资产。

额定值
0 0

目前没有任何评论。

成为第一个发表评论的人。