第七章 安全性
篇别:第一篇 基础知识
本章学习目标
- 建立 ACL → 记录规则 → 字段级权限 → 视图/菜单 的分层安全观。
- 能独立编写
ir.model.access.csv与ir.rule,并理解 全局规则与分组规则 的组合逻辑。 - 能识别 sudo、Controller、SQL、仅 invisible 等典型陷阱并给出修复思路。
- 了解 Odoo 19 统一权限 API(
check_access、has_access、_filtered_access等,以官方签名为准)。
导读:没有「单一开关」的安全
Odoo 安全是 纵深防御:即使菜单隐藏、字段 invisible,RPC 仍可能直达模型方法。因此 模型层 ACL 与记录规则 是底线;界面层只是体验与误操作防护。
7.1 访问控制列表(ACL)
7.1.1 知识要点
ir.model.access:回答「某 用户组 对某 模型 能否 增删改查」。- 无 ACL:非超级用户通常 完全无法 通过 ORM 访问该模型(超级用户绕过)。
- 多组权限:用户属于多组时,同一模型上 权限合并取并集(读/写/建/删任一允许则为允许,具体以 ORM 实现为准,建议用测试验证)。
- CSV 文件:
security/ir.model.access.csv,model_id:id引用model_<模型名点换下划线>形式的 XML id。
7.1.2 案例
案例 A:普通用户可读写建、不可删
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_library_book_user,library.book.user,model_library_book,base.group_user,1,1,1,0
案例 B:仅图书馆管理员可删
access_library_book_librarian,library.book.librarian,model_library_book,my_library.group_librarian,1,1,1,1
用户需同时满足:属于有 read 的组 且对记录通过 record rule;删除还需 perm_unlink。
7.1.3 截图占位


7.1.4 本节练习
- 简答:
perm_unlink=0时,超级用户与普通用户分别能否unlink? - 实操:新增组
group_library_readonly,仅perm_read=1,其余 0,用测试用户验证无法write。 - 判断:只要定义了 ACL,就无需记录规则。( )
参考答案提示:1. 超级用户可;普通用户不可。3. 错,多租户/多公司/行级隔离靠 rule。
7.2 记录规则(Record Rules)
7.2.1 知识要点
ir.rule:domain_force为 Python 表达式 或 domain 列表字符串,限制 可见/可操作 记录集。perm_read/write/create/unlink:可细分;未勾选表示该规则 不限制 对应操作(以界面逻辑为准)。- 全局规则:
groups为空时适用于所有人(慎用);分组规则 仅对列出的组生效。 - 多规则:同一模型多条规则通常 AND 合并(理解:记录须同时满足所有适用规则)。
7.2.2 案例
案例 A:仅看自己创建的书
<record id="library_book_rule_own" model="ir.rule">
<field name="name">图书:用户仅自己创建</field>
<field name="model_id" ref="model_library_book"/>
<field name="domain_force">[('create_uid','=',user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
</record>
案例 B:多公司标准形态(示意)
<field name="domain_force">['|',('company_id','=',False),('company_id','in', company_ids)]</field>
company_ids 为规则求值上下文中可用变量(以官方文档为准)。
7.2.3 截图占位

7.2.4 本节练习
- 判断:
sudo()后记录规则仍然生效。( ) - 实操:写一条规则:「经理组可看全部书,普通用户仅看
state=draft的书」(两组两条 rule 或一条带组,思考哪种更清晰)。 - 简答:规则
domain_force写错导致 所有用户看不到数据,如何快速恢复?
参考答案提示:1. 错。3. 超级用户登录关闭规则或改 XML 再 -u。
7.3 用户组
7.3.1 知识要点
res.groups:category_id决定设置里的分组;implied_ids 可继承子组。- 视图/菜单
groups:XML 属性,隐藏 UI;不替代 ACL。 - 字段
groups:模型字段上限制 读写(仍需 ACL 打底)。
7.3.2 案例
<button name="action_reset" type="object" string="重置"
groups="base.group_system"/>
internal_note = fields.Text(groups='my_module.group_manager')
7.3.3 截图占位

7.3.4 本节练习
- 简答:菜单
groups="sales_team.group_sale_salesman"与模型 ACL 仅group_user同时存在时,销售员能否从 RPC 读到数据? - 实操:新建「图书馆」应用分类与两个组:读者/管理员,并各挂不同菜单。
参考答案提示:1. 若能通过其他 action 打开同一模型且 ACL 允许,则能。
7.4 字段级权限(新增)
7.4.1 知识要点
对 薪资、密钥、身份证号 等字段,除 不可见 外,可配置 字段级访问(名称与入口以 19.0 为准:如 Field Access / ir.model.fields 相关安全扩展),限制 读/写 组。
导出、API、报表 仍须测试是否泄露。
7.4.2 案例
流程建议:在技术菜单创建字段访问规则 → 指定模型、字段、组、只读或可写 → 用普通用户测 read 返回字典中是否含该 key。
7.4.3 截图占位

7.4.4 本节练习
- 实操:为
res.partner自定义字段x_id_card限制仅group_hr可读。 - 简答:字段级只读能否被
fields_get元数据暴露字段存在性?敏感字段如何进一步处理?
参考答案提示:2. 可能暴露存在;可配合 ACL、独立模型或不在无关视图出现。
7.5 安全陷阱(新增)
7.5.1 知识要点
| 陷阱 | 说明 |
|---|---|
Controller + sudo + 用户 id |
未校验 该用户是否有权访问该 id |
仅 invisible |
前端隐藏,RPC 仍可读 |
| SQL 拼接 | 注入与越权 |
复制 method_route 无 CSRF |
状态变更应用 POST + token |
| 记录规则未测多公司 | 串库、空数据 |
7.5.2 案例
反面案例
# 危险
rec = request.env['library.loan'].sudo().browse(int(kw.get('id')))
return rec.read()
改进思路(示意)
rec = request.env['library.loan'].browse(int(kw.get('id')))
rec.check_access('read')
return rec.read()
或使用 request.env.user 下 _filtered_access 过滤后的记录集(以 19.0 API 为准)。
7.5.3 截图占位

7.5.4 本节练习
- 改错:将反面案例改为无
sudo并校验权限。 - 情景题:公开路由
auth='public'返回「今日借阅册数」如何既不泄露明细又防刷?
7.6 Odoo 19 权限新方法(新增)
7.6.1 知识要点
在业务代码中优先使用统一入口:has_access(布尔)、check_access(不通过抛异常)、_filtered_access(返回当前用户可见子集),减少手写 if not user.has_group 的分散逻辑。
方法名与参数 以 ORM / 安全相关文档 为准。
7.6.2 案例(伪代码)
records = self.env['library.book'].search(domain)
records = records._filtered_access('read')
7.6.3 截图占位

7.6.4 本节练习
- 实操:在报表方法开头对
model调用check_access('read'),用无权限用户跑单元测试断言AccessError。 - 简答:
_filtered_access与search+sudo再filtered的差异?
本章综合练习
- 威胁建模:为「借阅」模块做 STRIDE 简表(至少 欺骗、越权、信息泄露 各一条与缓解)。
- 渗透思路:普通用户能否对无
createACL 的模型调用create?如何用 HttpCase 或 RPC 脚本 验证? - 设计题:「读者只能借自己的书,管理员可看全部」——写出需要的 组、ACL、规则 提纲(不必写全 XML)。
- 拓展:阅读官方 Security 文档中 Superuser 与 Testing 章节,记录一条测试建议。
本章对应白皮书目录:第七章 安全性。