Odoo 19 权限怎么管才不漏?六维权限矩阵、ir.rule 记录规则与字段级控制实战 2026

Odoo 原生只有用户组、模型级 ACL 和记录规则三层权限,撑不住真实企业的数据隔离需求。本文给出一套已在生产环境验证的六维权限矩阵方法:用三张 Excel 表把权限需求收敛成可生成的代码,再落到 ir.model.access、ir.rule、字段 groups 与视图继承四个实现层,覆盖用户、角色、字段、关注人、项目经理与 Odoo 管理员六个维度,并整理 8 个高频踩坑点与故障排查表,照做即可把权限体系一次做对。
企业 Odoo 六维权限矩阵

一、先认清 Odoo 原生权限的三层结构

很多企业装完 Odoo 之后,管理员在「设置 → 用户」里勾了半天组,回头还是被业务部门追问:为什么销售能看见别的销售的项目?为什么仓库文员能改采购单价?问题的根源是,多数人只用了 Odoo 权限体系里最粗的那一层。

Odoo 原生的权限控制,严格说只有三层,缺一不可,但也仅此而已:

第一层:用户组(res.groups)。决定一个人能进哪些菜单、用哪些功能,比如「销售 / 用户」「库存 / 管理员」。这是界面上唯一能直接勾的东西,也是大多数人以为的「权限管理」。

第二层:模型级访问控制(ir.model.access)。决定某个组对某张表(模型)能不能读、写、建、删,粒度是「整张表」。自定义模块必须自己写,原生界面不管这件事。

第三层:记录级规则(ir.rule)。决定在整张表里,这个人能看到哪些「行」,比如「只看自己负责的项目」。写在 XML 里,界面上藏得很深。

这三层各管一段,谁也替代不了谁。但真实企业的需求往往长这样:同一个项目列表,项目经理要能改,财务只能看金额相关字段,普通成员只能看自己参与的任务——这已经同时压到了三层以上,还叠加了「按项目类别隔离」「关注人可见」这类跨表逻辑。这时候,靠界面勾选是永远做不对的,必须先把需求整理成矩阵,再逐层落地。

二、六维权限模型:先把需求归类,再谈实现

我们在多个生产环境里收敛出一套「六维」归类法。它的价值不在技术上,而在于沟通:业务方提的任何一条权限诉求,都能归到六维之一,你不用每次都从零开始想「这个该怎么实现」。

六维模型如下表:

维度解决什么问题落在哪一层
1. 用户维度某个具体的人的例外权限直接加入用户组,慎用
2. 角色维度岗位能做什么:销售 / 采购 / 财务 / 项目经理res.groups + ir.model.access
3. 字段维度同一张表里,哪些字段谁能看、谁能改字段 groups 属性 + 视图继承
4. 关注人维度我关注 / 参与的单据,即使不是负责人也要能看ir.rule 查 message_follower_ids
5. 项目经理维度我负责的项目下的任务、工时、成本全部可见ir.rule 跨表关联
6. Odoo 管理员维度谁能修改权限本身——必须单列、必须极小base.group_system + 变更审批

使用方法很简单:需求评审时,把业务方说的每一条「谁能看什么、谁能改什么」逐条贴上维度标签。比如「财务要看到项目成本价」归第三维,「出差的同事要能看自己跟的单」归第四维,「分公司只能看本分公司的数据」本质是第五维加多公司规则的组合。

归类完你会发现,80% 的需求集中在第二、三、五维,而最容易出安全事故的恰恰是第六维——谁有权修改权限本身。这一维必须单独立规矩:Odoo 管理员账号极少数人持有、开启双因素验证、所有权限变更走审批记录。权限体系自己没有权限约束,等于整个体系建在沙子上。

三、Excel 权限矩阵:三张表把需求变成代码

矩阵不是画给人看的花架子,它的正确用法是当成源文件:Excel 填完,用脚本机械翻译成 Odoo 的 CSV 和 XML,人和代码各干各的,抄写错误为零。我们固定用三张表。

3.1 角色定义表

一个角色一行,写清楚角色代码、显示名、继承哪些原生组。角色代码一旦定下就不要改,后面所有 CSV、XML、视图都引用它。继承关系要写实:比如「项目经理」继承 base.group_user 加 project.group_project_manager,这样原生功能不用重新授权。

3.2 模型 × 角色 CRUD 矩阵

行是模型,列是角色,格子里填「读 / 增删改查 / 无」。这张表就是 ir.model.access.csv 的原始数据。填表时有个实用口诀:先全部填「无」,再一格一格往里加——从「全部可读再收权」出发的表,十有八九会漏收。

3.3 字段可见矩阵

行是「模型.字段」,列是角色,格子只有「可见 / 不可见」。这张表专门管成本价、毛利率、工资这类敏感字段,是第三维(字段维度)的落地依据。

三张表填完,剩下的就是写生成脚本:表 2 逐行输出 CSV,表 3 逐行输出字段覆写 XML。脚本半天就能写好,之后每次新增角色或模块,改 Excel、跑脚本、提交代码,权限变更从此走版本管理,谁改了什么、什么时候改的,Git 记录一清二楚。

四、模型级权限:ir.model.access.csv 四列写法

模型级权限放在模块的 security/ir.model.access.csv 里,表头固定,一个字符都不能差:

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink

access_prj_sales,project.project sales,model_project_project,group_sales_role,1,0,0,0

access_prj_pm,project.project pm,model_project_project,group_pm_role,1,1,1,1

access_acc_fin,account.move fin,model_account_move,group_fin_role,1,1,1,1

三个必须记牢的点,都是实际踩出来的:

第一,没有 ACL 就是一切皆无。自定义模型哪怕在界面上勾了再多组,只要没有 access 记录,任何调用直接抛 AccessError。排查「新建项目报错」这类问题时,第一反应就应该是查这个文件里有没有对应模型的记录。

第二,group_id 留空等于全站放行。包括门户用户和公开用户。除非你明确要这个效果,否则这一列永远不要留空。

第三,Odoo 18 起用户组的分类字段改成了 privilege_id,老教程里的 category_id 写法在 19.0 上已经不适用,直接照抄老代码会导致权限界面的分组显示错乱。涉及版本差异的写法,动手前先核对官方文档(本文第十一节给了清单)。

五、记录级权限 ir.rule:OR 与 AND 的语义必须背下来

记录规则决定「这个人能看到哪些行」。核心是 domain_force 里的一串域表达式,user 变量代表当前登录用户。先看两个最常用的场景。

5.1 场景一:只看自己负责的项目

<record id="rule_project_own" model="ir.rule">

  <field name="name">项目:仅本人负责</field>

  <field name="model_id" ref="project.model_project_project"/>

  <field name="domain_force">[('user_id','=',user.id)]</field>

  <field name="groups" eval="[(4, ref('group_pm_role'))]"/>

</record>

5.2 场景二:负责人或关注人可见

<record id="rule_task_visible" model="ir.rule">

  <field name="name">任务:负责人或关注人</field>

  <field name="model_id" ref="project.model_project_task"/>

  <field name="domain_force">['|',('user_ids','in',[user.id]),('message_follower_ids','in',[user.partner_id.id])]</field>

  <field name="groups" eval="[(4, ref('base.group_user'))]"/>

</record>

5.3 多条规则的叠加语义(最容易翻车的地方)

Odoo 对不同类型的规则采用完全不同的逻辑运算,这个语义必须背下来:

规则类型多条规则之间实际效果
组规则(global=False)OR(或)用户所在任意一个组放行,即可看到该记录
全局规则(global=True)AND(与)对所有人生效,叠加后进一步收紧

实操含义:组规则之间是「放宽」,全局规则是「收口」。一套健康的权限体系,应该在关键业务模型上放一条 global=True 的收口规则(比如强制 company_id 匹配),再用组规则按角色放宽。只写组规则、不写全局规则,等于大门敞开只靠房间锁。

还有两个致命细节:其一,记录规则对超级用户和 sudo() 调用不生效。代码评审时看到业务逻辑里随手写 sudo(),基本可以认定这层权限已经被拆了——只在定时任务、数据修复这类后台场景允许使用。其二,域里引用了不存在的字段,规则会静默失效。字段改名升级之后,规则不会跟着改,这属于最高优先级的回归测试项。

六、字段级权限:groups 属性是唯一正路

「成本价只有财务能看」这类需求,正确做法只有一个:在字段定义上加 groups,通过 _inherit 覆写实现,绝不去改原生源码:

standard_price = fields.Float(groups='group_fin_role')

加上之后会发生两件事。第一,视图层面,无权限用户的表单、列表、筛选、导出里都不会出现该字段;第二,也是关键区别——ORM 层面同样被拦截。没有该组的用户通过接口直接读取这个字段,得到的不是空值,而是访问错误。也就是说,界面隐藏和接口防护是一起生效的,对方绕不过去。

这比常见的三种错误做法安全一个量级:视图里设 readonly(只挡界面不挡接口);前端 CSS 藏字段(开发者工具一秒破);计算字段返回空(逻辑入侵业务,维护成本极高)。

实操建议:把表 3(字段可见矩阵)里所有「不可见」格子集中生成一个覆写文件,统一挂在 models/field_security.py,一个文件管全部敏感字段,别散落在各个继承文件里。

🔧 我整理的软件库

这些年折腾服务器、虚拟化和开发环境,装过的系统镜像、运维工具、开发套件、数据库与中间件,我都归档在自建的文件库里,持续补充新版本。没有弹窗广告,不强制注册,需要什么直接取。

进入软件库 →

常用工具随手可取 · 不定期补档

七、视图层隐藏只是第三道防线

按钮和菜单的显隐,用视图继承的 groups 属性即可,比如把「确认订单」按钮限定给项目经理:

<xpath expr="//button[@name='action_confirm']" position="attributes">

  <attribute name="groups">group_pm_role</attribute>

</xpath>

但必须建立一个共识:视图隐藏是体验优化,不是安全措施。按钮藏了,方法还在,懂技术的人换个客户端直接调 RPC 照样执行。正确的叠法是三层防线:

第一层(安全):ir.rule 让对方根本没有那条记录的写权限——记录都看不见,方法调了也是空操作;第二层(安全):业务方法内做 check_access_rights / check_access_rule 或手工条件校验,多公司场景校验 company_id;第三层(体验):视图隐藏,让普通用户看不到不该看的按钮。

验收标准只有一句话:拿一个最小权限的测试账号,绕过界面直接调接口,所有越权操作必须全部被拒。用管理员账号自测权限,等于没测。

八、改了不生效?noupdate 与升级参数

权限改完「没反应」,九成出在生效机制上,三种情况对号入座:

情况一:XML 里的规则改了,升级后没变化。记录带 noupdate="1" 标记时,模块升级不会覆盖已存在的记录。处理办法:界面上删掉旧规则再升级,或者把 noupdate 去掉让代码接管。

情况二:新加的 CSV 没导入。文件加了但没执行升级。Docker 部署下的标准动作:

docker exec -it odoo19-enterprise odoo -d 数据库名 -u 你的模块名 --stop-after-init

docker restart odoo19-enterprise

情况三:界面上手改过权限,下次升级被还原。这是设计如此——代码里定义的记录优先。结论也只有一句:权限规则只写代码、走 Git,界面上不做任何长期修改。

九、故障排查表与 8 个高频踩坑点

权限问题的表现集中且典型,先查表再动手:

现象最可能的原因处理动作
调用直接报 AccessError模型没有 ACL 记录补 ir.model.access.csv,注意 group_id 别留空
列表里出现不该看到的数据缺少 ir.rule 或组规则被 OR 放行补全局收口规则,用最小权限账号复测
该看到的记录看不到全局规则把组规则也收窄了检查 global 规则的域是否过严
改了 XML 升级后没变化记录带 noupdate=1删旧记录再升级,或去掉 noupdate
字段在表单上仍可见视图里显式写了该字段视图继承中给字段加同样的 groups
导出能拿到隐藏字段只在视图层做了隐藏字段级权限必须落在字段 groups 上

除此之外,8 个高频踩坑点按出现频率排序:

坑 1:只写 ir.rule 不写 ACL。直接 AccessError。顺序永远是:先给模型级 CRUD,再收记录级。

坑 2:域表达式引用了不存在或改名的字段。规则静默失效,比报错更危险。字段改名必须同步过一遍规则。

坑 3:只写组规则,没有全局收口规则。组规则之间是 OR,多一个组就多一条放行路径,最终一定漏。

坑 4:业务代码里滥用 sudo()。整层记录权限被绕过。全局搜索一遍 sudo(),逐个确认,前端链路一律清零。

坑 5:字段加了 groups,表单上还能看见。因为视图里显式写了该字段——视图继承里也要加同样的 groups。

坑 6:多公司规则与自定义规则打架。全局规则之间是 AND,会把自己写的组规则也进一步收窄,出现「明明该看到的看不到」。多公司场景要单独画矩阵。

坑 7:在界面上调权限图省事。下次升级被代码覆盖,白改还引入「两边不一致」的隐患。

坑 8:只做视图隐藏就宣布完工。接口层裸奔,一次渗透测试就现原形。

十、三种做法对比:矩阵法赢在哪

同样是做权限,三种常见路线的长期成本差异很大:

对比项界面勾选矩阵法(本文)全塞管理员组
上手速度最快前期多半天最快
字段级控制做不到天然支持做不到
变更可追溯无记录Git 全记录无记录
新人接手成本靠口口相传看矩阵即懂无人说得清
审计合规弱可出报告几乎为零
适用规模个人 / 演示团队与企业都不建议

我的建议很直接:两人以上的团队、模块数量超过三个,一律走矩阵法。它的前期投入比界面勾选多半天,但换来的是权限变更可评审、可回滚、可审计——这三件事在权限事故复盘时值回所有投入。不建议的做法是第三种「全塞管理员组」:短期最省事,长期等于没有权限体系,而且一旦出数据泄露事故,你连「谁在什么时候给了谁权限」都说不清楚。

本文涉及的版本差异(如用户组分类字段的变化)属于随版本演进的部分,落地前请以第十一节官方文档的当前版本为准,不要凭记忆硬写。

十一、官方参考 URL 清单(发布前请实时核对)

以下入口用于核对版本差异与最新参数,动手实施前建议逐个打开确认:

① 安全机制总览(访问权限 / 记录规则 / 字段权限):
https://www.odoo.com/documentation/19.0/developer/reference/backend/security.html

② ORM 与域表达式(domain 写法):
https://www.odoo.com/documentation/19.0/developer/reference/backend/orm.html

③ 视图架构与 xpath 继承:
https://www.odoo.com/documentation/19.0/developer/reference/user_interface/view_architectures.html

④ Odoo 19 开发者文档总目录:
https://www.odoo.com/documentation/19.0/developer.html

⑤ 用户与权限管理(应用侧):
https://www.odoo.com/documentation/19.0/applications/general/users.html

结语

权限是信息化工程里最难返工的一块。数据模型错了可以加字段,界面丑了可以换主题,而权限设计错了,你要回头修改每一处「默认所有人都能看到」的业务假设,成本是几何级上升的。

所以从第一天起就做三件事:把六维矩阵画出来、把规则写进代码、拿最小权限账号去测。做完这三步,后面加人、加部门、加公司,基本不会翻车。

如果你正在推进 Odoo 落地,或者手上的系统权限已经一团乱麻,欢迎在评论区说说你的场景,也可以加我微信 17712677007 一起探讨。

👉 延伸阅读:Odoo 数据备份

权限体系做好之后,下一步就是数据安全。Odoo 的数据库和上传文件是两套完全不同的存储,备份策略要分开设计——我们整理过一套含 Crontab 自动化与保留策略的完整方案,建议配合本文一起看。

查看 Odoo 备份实战教程 →

✍️ 关于作者

IT 峰哥,互联网技术从业者。日常折腾服务器、虚拟化、数据库与企业级应用,关注开源系统的二次开发与基础设施落地。这里记录的是踩过的坑和验证过跑得通的方案,不是转述文档。

交流:微信 / 手机 17712677007(注明来意,看到会回)

文中方案如有疏漏,欢迎在评论区指正 · 技术问题欢迎交流

默认

RustDesk 内网无公网 IP 怎么搭中继?端口映射、frp 中转与多分支机构组网实战

2026-10-23 19:35:24

默认

群晖 NAS 勒索病毒防护与应急响应指南:12 项加固动作 + 中招处置五步 2026

2026-10-29 21:54:13

❯
搜索