4.1 ACL 回答什么问题
ACL 回答的是:用户对整个模型是否拥有某种 CRUD 能力? 它不关心具体记录、状态或部门。
Odoo 的四种标准操作是:
| Odoo 名称 | 通常含义 |
|---|---|
read |
读取、搜索、打开 |
write |
修改已有记录 |
create |
创建记录 |
unlink |
删除记录 |
“确认订单”“审批费用”“会计过账”不是第五种 ACL,必须由业务方法控制。
4.2 ir.model.access 的重要字段
模型定义在 odoo/addons/base/models/ir_model.py:2006-2019:
| 字段 | 说明 |
|---|---|
name |
ACL 名称 |
active |
禁用时不参与判定;比删除原生 ACL 更适合临时停用 |
model_id |
目标 ir.model |
group_id |
适用组;空值代表所有用户 |
perm_read |
是否授予 read |
perm_write |
是否授予 write |
perm_create |
是否授予 create |
perm_unlink |
是否授予 unlink |
4.3 ACL 是 grant 的并集
运行时 _get_allowed_models(uid, mode) 直接查询所有 active 且 perm_mode=True 的 ACL,只要 group_id 为空或属于用户组就把模型加入允许集合,见 ir_model.py:2067-2086。
假设用户同时拥有 A、B 两组:
| 组 | Read | Write | Create | Unlink |
|---|---|---|---|---|
| A | 1 | 0 | 1 | 0 |
| B | 0 | 1 | 0 | 0 |
| 最终有效权限 | 1 | 1 | 1 | 0 |
B 组中的 Read=0 不是拒绝 read,只是 B 没有授予 read;A 的 grant 仍然生效。原生 ACL 没有 deny、优先级或“经理组覆盖用户组”的概念。
4.4 CSV 配置
标准文件为 security/ir.model.access.csv:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_document_user,document.user,model_demo_document,demo.group_document_user,1,1,1,0
access_document_manager,document.manager,model_demo_document,demo.group_document_manager,1,1,1,1
注意:
model_demo_document是模型_name = 'demo.document'自动生成的 external ID。group_id要使用稳定 XML ID。- Manager 若 implied User,两条 ACL 都会匹配,最终仍是并集。
- 删除模块自带 ACL 后,模块升级可能重建;需要停用时优先考虑
active=False,并评估升级数据策略。
4.5 无组 ACL 的风险
group_id 为空会给所有用户类型授权,包括门户或公共用户,只要后续规则没有限制。Odoo 18 仍支持它,但在创建有权限勾选的无组 ACL 时会输出 deprecated 警告,源码见 ir_model.py:2131-2141。
新模块应始终明确组。特别是网站模型,不要因为“控制器里会判断 token”就给整个模型一个无组 write/create ACL。
4.6 ACL 的源码调用
recordset.check_access(operation)
-> recordset._check_access(operation)
-> env['ir.model.access'].check(model_name, operation)
-> _get_allowed_models(uid, operation) # 有缓存
核心位置:
- 统一入口:
odoo/models.py:4370-4428。 - ACL 检查:
ir_model.py:2088-2102。 - 拒绝信息和可授权组:
ir_model.py:2104-2121。 - ACL 变更清缓存:
ir_model.py:2123-2149。
Odoo 18 中 check_access_rights() 已废弃,推荐使用空 recordset 的新统一 API:
self.browse().check_access("create")
can_read = self.browse().has_access("read")
check_access_rule() 和 _filter_access_rules() 也已废弃,分别改用 check_access() 和 _filtered_access()。
4.7 ACL 不能表达的事情
ACL 无法表达:
- 只能看自己的订单;
- 草稿可以改,已审批不能改;
- 金额超过十万元需总经理;
- 不能审批自己提交的费用;
- 只能修改备注,不能修改金额;
- 临时授权到某日失效。
前两类部分可由记录规则表达,复杂状态、字段写策略和职责分离必须进入业务代码或增强策略层。
老赵解读
ACL 的定位很朴素:只回答某类用户能否对某个模型做增删改查。它是能力底座,不是数据范围,也不是审批制度。设计时宁可让 ACL 保持少而稳定,再用记录规则和业务方法补足范围与条件;不要为了表达每一种组织范围,复制出大量近似 ACL 和用户组。
目前没有任何评论。