先给你一个不会乱的框架
Odoo 权限最好按两层来记:
- 能不能操作这个模型 → Access Rights(
ir.model.access) - 能操作这个模型里的哪些记录 → Record Rules(
ir.rule)
如果你脑子里先没有这条分层,后面就很容易把所有报错都理解成“系统抽风”。
实际上,大多数权限问题都能落回这两个问题:
- 你有没有这个模型的读写删建权?
- 就算有,你能碰到的是不是当前这批记录?
Groups 不是最终权限,但它是入口
很多人第一次接触 Odoo,会把 group 直接当成权限本身。
其实 group 更像“权限包的挂钩点”。
它会影响至少三类东西:
ir.model.access:模型级 CRUD 权限ir.rule:记录级过滤规则- 视图 / 菜单 / 按钮的显示逻辑
所以 group 本身不是终点,而是把安全策略挂到用户身上的桥。
第一层:Access Rights 决定“你是否能进门”
模型级权限说的是:
- 对某个 model 能不能 read
- 能不能 write
- 能不能 create
- 能不能 unlink
如果这层没有放行,后面的 record rule 根本没机会发挥。
也就是说:
Access Rights 是门禁卡,Record Rule 是门里之后的活动范围。
这也是为什么很多人明明配了 record rule,用户还是报没权限——因为他连模型级 read 都没有。
第二层:Record Rule 决定“进门后能看到哪几条”
ir.rule 的核心就是一个 domain。
源码中 IrRule._eval_context() 会给 domain 提供常见上下文:
usercompany_idcompany_ids
所以你在规则里经常会写到:
- 只能看自己负责的记录
- 只能看自己公司的记录
- 只能看被分配给自己的单据
这类限制都不是 access rights 干的,而是 record rule 干的。
全局规则 vs 分组规则:这是最容易踩坑的地方
源码里有个特别关键的实现:
- global rules(没有 group)会一起做 AND
- group rules(绑定 group)先做 OR,再整体并到全局约束里
这是理解 Odoo 记录规则的核心。
直白翻译
假设你有:
- 全局规则 A:只能看本公司数据
- 全局规则 B:只能看 active 记录
- 分组规则 C:销售员可看自己的单
- 分组规则 D:经理可看本团队的单
最终效果更像:
A AND B AND (C OR D)
而不是所有规则都简单 OR 或简单 AND。
这就是为什么你“多加一条规则”后,结果可能不是放宽,反而更窄。
为什么多公司问题总像权限问题
在 ir.rule 源码里,_eval_context() 和错误构造逻辑都明确考虑了 company_id / company_ids。
这意味着很多 AccessError 不是“你角色不够”,而是:
- 记录属于别的公司
- 当前启用公司上下文不对
- 规则 domain 把记录过滤掉了
所以多公司场景下,用户说“我明明有权限,为什么打不开”,你第一反应应该是:
这是不是 company context 问题?
而不是立刻改 group。
_compute_domain():Odoo 真正把规则拼起来的地方
在 IrRule._compute_domain() 里,Odoo 会:
- 找出当前模型、当前操作模式匹配的规则
- 区分全局规则和分组规则
- 计算每条规则的 domain
- 组合成最终 domain
- 再去 search / read 时统一应用
所以 record rule 不是“报错时才检查一次”的小钩子,它其实深度参与日常查询。
这也是为什么规则写差了,不只是报错,性能和列表结果也会一起出问题。
为什么有时是“看不到”,有时是“点进去报错”
这取决于规则是在搜索阶段就把记录过滤掉了,还是在后续操作阶段才触发失败。
典型表现:
- 列表里压根没有 → search 时 domain 已经拦掉
- 列表能看到但点开报错 → 某个后续 read/write 操作命中了更严格约束
源码里 _make_access_error() 还会尽量拼出更友好的报错信息,甚至提示可能是 multi-company 问题。
所以前端症状不同,底层触发位置也可能不同。
sudo() 为什么既好用又危险
你在 Odoo 源码里会经常看到 sudo()。
它的作用很直接:
- 跳过普通用户权限边界
- 让系统流程能继续推进
它适合用在:
- 业务流程内部创建下游对象
- 系统维护或后台计算
- 需要稳定履约但不希望卡在操作者个人权限上的场景
但危险也非常明显:
- 如果你在不该
sudo()的地方用了它 - 用户原本不该看到的数据也可能被带出来
- 定制代码会悄悄绕过 record rule
所以经验法则是:
对执行对象适度
sudo(),对用户可见结果保持克制。
一套特别实用的排查顺序
遇到权限问题时,不要上来就乱加 group。按这个顺序看:
1. 用户属于哪些 groups
先确认入口包。
2. 模型级 access rights 有没有对应 CRUD
没这层就别往下想。
3. 当前操作是 read / write / create / unlink 哪一种
record rule 是分 mode 的。
4. 当前模型有哪些生效的 ir.rule
尤其注意全局规则。
5. 规则 domain 里是否带了 company_id、user.id、负责人字段
这往往是根因。
6. 是否有 sudo() 或定制代码改变了安全边界
很多“偶发权限问题”其实是定制代码把链路切裂了。
一句话记忆法
把 Odoo 权限体系记成一句话:
Access Rights 负责决定你能不能操作这个模型,Record Rules 负责决定你能操作这个模型里的哪些记录。
抓住这句,80% 的权限问题都会立刻变得可分析。
DISCUSSION
评论区