权限分层

Odoo 权限不是一把锁:ACL、record rule、组可见性和 sudo 的完整分层

把 ir.model.access、ir.rule、视图 groups 和 sudo 放到一张图里,解释谁管模型、谁管记录、谁只是隐藏界面。

Odoo 开发 框架
进阶 开发者 3 分钟阅读
0 评论 0 点赞 0 收藏 4 阅读

先说结论

Odoo 的权限不是一层,而是至少四层:

  1. ACL(ir.model.access:这个模型能不能读、写、建、删
  2. 记录规则(ir.rule:在允许访问模型之后,哪些具体记录能看
  3. 视图 groups:界面上哪些按钮、字段、菜单该显示给谁
  4. sudo():有意识地绕过权限检查,用于特定内部逻辑

最常见的错误就是把这四层混在一起。

比如:

  • 以为 UI 看不到,就代表后端也访问不到
  • 以为有 ACL,就不需要 record rule
  • 以为 sudo() 只是“少写点权限代码”,不会影响数据边界

实际上,它们解决的是不同问题。


第 1 层:ACL 决定“能不能碰这个模型”

odoo/addons/base/models/ir_model.py 里,ir.model.access 维护的是模型级权限。

它回答的是非常基础的问题:

这个用户对这个 model,是否有 read / write / create / unlink 权限?

源码里的 check() 会先判断当前用户是否在允许组里,如果没有,就直接抛错。

这意味着 ACL 是第一道闸门:

  • 没有 ACL,连模型层的门都进不去
  • 有 ACL,也不代表能看见所有记录

所以 ACL 是“模型访问许可”,不是“数据行访问许可”。


第 2 层:record rule 决定“能看到哪几行”

odoo/addons/base/models/ir_rule.py 里,_compute_domain() 会把所有适用的记录规则合成为一个 domain。

这里最关键的规则是:

  • global rules:全局规则,彼此是 AND
  • group rules:组规则,先 OR,再与 global rules AND

换句话说,记录规则不是“加一条就完事”,而是有合并语义的。

再加上 check_access() 在真正检查记录时,会把规则域套到实际记录集上,过滤出 forbidden records。

所以你看到的结果通常不是:

  • “有没有权限”

而是:

  • “这个记录集里,哪些能看,哪些不能看”

这也是为什么记录规则经常和多公司、仓库、团队、销售区域等边界一起出现。


第 3 层:视图 groups 只是 UI 可见性

ir.ui.view 的 postprocess 阶段,Odoo 会根据 groups 把一些节点从前端 arch 里移掉,或者调整按钮权限标记。

这很有用,但它只负责“界面展示”。

它不等于后端安全。

也就是说:

  • 你把按钮藏起来,不代表 API 调不到
  • 你把字段隐藏掉,不代表用户不能通过别的入口写入

真正的安全边界,还是要回到 ACL + record rule + 后端业务校验。

所以,groups 适合控制“看见什么”,不适合单独承担“能不能做”的责任。


第 4 层:sudo() 是明确的绕过,不是“普通快捷方式”

odoo/orm/models.py 里,check_access() 会先查 ACL,再查规则。

但如果环境已经是 env.su,很多检查会直接短路。

这意味着 sudo() 的意义非常强:

  • 它不是“临时提高一点点权限”
  • 它是“显式切换到超级用户语义”

因此,写代码时要问自己:

  1. 为什么这里必须绕过权限?
  2. 绕过以后,返回给前端的数据会不会过宽?
  3. 有没有必要在 sudo 后再做一次业务过滤?

如果不想清楚,sudo() 很容易成为数据泄漏的入口。


一条完整链路长什么样

odoo/orm/models.py 里的 _check_access() 很直白:

  1. 先查 ir.model.access
  2. 再查 ir.rule
  3. 只要任一层不通过,就报错

也就是说:

ACL 管“模型层”,record rule 管“记录层”。

这两个阶段不是二选一,而是串联关系。


常见误区:把视图 groups 当成安全边界

这个误区非常常见。

例如:

  • 只在按钮上加 groups="base.group_system"
  • 就以为普通用户完全不可能触发对应逻辑

实际上,如果那个逻辑被别的 RPC、action、server action、导入工具或者自定义代码调用,UI 限制根本不够。

所以“前端看不见”只能算体验控制,不能算安全控制。


调试权限问题时,先按这个顺序看

  1. 先看 ACL:模型有没有基本读写权限
  2. 再看 record rule:是不是规则域把记录过滤掉了
  3. 再看 sudo():是不是某段逻辑绕过了检查
  4. 最后看 view groups:只是界面为什么没显示

这样排查,基本不会把“UI 问题”和“数据权限问题”混成一团。


一个实用的判断标准

如果你在设计权限边界,可以用一句话自检:

这个限制是“能不能碰模型”,还是“能不能看到记录”,还是“界面要不要显示”?

只要这个问题没分清,权限设计就很容易乱。


总结

Odoo 权限的正确理解方式是分层:

  • ACL 先决定模型是否可访问
  • record rule 再决定哪些记录可访问
  • view groups 只负责 UI 呈现
  • sudo() 是显式绕过,不是轻量优化

把这四层分开,你就不会再把“看不见”误当成“访问不到”。


English sidecar

The short version

Odoo permissions are layered. They are not one lock.

  1. ACL (ir.model.access) decides whether a user can read, write, create, or delete a model
  2. Record rules (ir.rule) decide which specific records are visible after model access is granted
  3. View groups decide what the UI should show
  4. sudo() is an explicit bypass for special internal logic

A very common mistake is to mix these layers up.


Layer 1: ACL controls the model

ir.model.access answers the basic question:

Can this user touch this model at all?

If the answer is no, Odoo stops before record rules even matter.

So ACL is the model-level gate, not the row-level filter.


Layer 2: record rules control the records

ir.rule._compute_domain() merges all applicable rules into a domain.

The key behavior is:

  • global rules are ANDed
  • group rules are ORed together first, then ANDed with globals

That means record rules are not just “one more restriction”. They have merge semantics.


Layer 3: view groups are only UI visibility

ir.ui.view post-processing can remove or tweak nodes based on groups.

Useful? Absolutely.

But it only controls presentation.

Hiding a button does not protect the backend API.


Layer 4: sudo() is an explicit bypass

In odoo/orm/models.py, access checks first consult ACLs and then record rules.

But once the environment is sudoed, those checks short-circuit.

So sudo() is not a small convenience. It is a strong semantic change.

Always ask:

  • Why is bypassing necessary here?
  • Will the returned data be too broad?
  • Should I still apply business filtering after sudo?

Practical debugging order

When something is denied, check in this order:

  1. ACL
  2. record rules
  3. sudo() usage
  4. view groups

That keeps UI problems and data-security problems separate.


Takeaway

Odoo permissions are easiest to understand if you keep the layers separate:

  • ACL = model access
  • record rules = record access
  • view groups = UI visibility
  • sudo = deliberate bypass

If you treat “not visible” as “not accessible”, you will eventually debug the wrong layer.

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。