---
title: "Odoo 20 权限迁移：多公司隔离验收"
canonical: https://wavect.io/zh/blog/odoo-20-company-access-migration-tests/
language: zh
description: "用角色与公司矩阵检查 Odoo 20 权限迁移。对照 16 个已执行的本地政策用例，审查转换警告，区分已激活与当前公司，并在升级数据库验证允许和拒绝访问。"
image: "https://wavect.io/img/blog/headers/header_odoo-20-company-access-migration-tests.png"
author: ["Kevin Riedl"]
published: "2026-11-05"
updated: "2026-11-05"
reviewed: "2026-11-05"
---

# Odoo 20 权限迁移：如何验收多公司隔离？

[**返回**](/zh/blog/overview/)

[![Kevin Riedl](/img/team/kevin.webp)](/zh/team/kevin-riedl/)

[Kevin Riedl](/zh/team/kevin-riedl/) https://linkedin.com/in/wsdt

11 分钟 阅读 · 2026年11月5日 最近审核 2026年11月5日

[**下一篇**](/zh/blog/odoo-email-pdf-quotation-review/)

要点速览

按获批角色与公司矩阵验收 Odoo 20 权限迁移，配对测试允许和拒绝操作。检查组授权与全局限制，记录已激活及当前公司，并单独核对公司依赖值。16 个本地 Python 用例仅说明虚构政策行为；真实 Odoo 矩阵仍为 NOT_RUN，需在升级构建执行。

下文虚构示例中，用户和记录都没有变，一次简单粗暴的权限改写却把“拒绝”变成了“允许”。业务政策没有改变，授权组合方式变了。

**只有获批角色与公司矩阵在升级数据库上通过允许和拒绝两类用例，才能接受 Odoo 20 权限迁移。** 先检查转换后的授权及全局限制，再分别验证已激活公司范围与当前公司取值。安装成功或管理员能浏览页面，都不能提供这些证据。

**资料核查日期：2026年11月5日。** 我们检查了 Odoo 19、20 官方文档、20.0 访问实现及源码转换脚本，并运行了 16 个虚构 Python 政策用例。没有运行 Odoo、数据库升级或官方转换器。下载的原生验收矩阵仍为 `NOT_RUN`。

## Odoo 20 的访问控制发生了什么变化？

Odoo 20 将操作和记录域纳入同一个访问模型。权限迁移需要审查转换后各项授权组合起来的含义，不能只看改名后的安全文件能否加载。保留获批政策作为参照，并逐个角色比较实际结果与预期要求。

官方 [20.0 安全参考](https://github.com/odoo/documentation/blob/20.0/content/developer/reference/backend/security.rst) 以组、操作和域定义 `ir.access`。带组条目授予访问，无组条目限制访问。 [19.0 参考](https://github.com/odoo/documentation/blob/19.0/content/developer/reference/backend/security.rst) 则描述模型级 ACL 授权之后再应用记录规则。

清点自定义安全记录及依赖它们的业务方法。记录每条配置实现哪项政策。例如，“负责人可读本公司自己的案例”和“审核人可读已激活公司的全部案例”并不相同，即使两类用户都能打开同一菜单。

[Odoo 迁移验收指南](/zh/blog/odoo-migration-acceptance-reconciliation/) 覆盖数据和流程延续。本文聚焦权限：订单迁移得再准确，如果错误身份也能读取，仍不可接受。

## 组授权和全局限制怎样组合？

对于普通访问检查，一条记录需要至少命中一个组授权，并满足所有适用的全局限制。示例中，宽泛授权会增加可读记录，而全局公司限制仍约束其范围。单独的限制不会授予访问。应测试组合效果，不能只逐条检查配置。

模型将决定表示为：

```
至少一个匹配的组授权
并且
满足每一项适用的全局限制
```

虚构组 `own_reader` 只授权用户 7 读取自己拥有的记录。独立的全局限制将记录范围限定在已激活公司。用户可读 `A-OWN`，不能读 `A-OTHER`。增加 `broad_reader` 后，第二条也变得可读，因为出现了另一项匹配授权。

现在保持公司 B 未激活。全局公司限制存在时，宽泛组仍不能读取 `B-OWN`。在故意错误的模型配置中移除该限制，同一记录就可读了。这项测试暴露的是示例缺口，不表示 Odoo 默认缺少这条边界。

还要测试合理的允许访问。示例并列要求“只能 A”和“只能 B”的两条全局限制，会阻止本来合法的记录。如果只测禁止访问，可能把这种坏配置当作成功。每项重要拒绝都应搭配一个允许对照，证明用户仍能工作。

## 测试应记录哪些公司上下文？

分别记录用户获授权加入的公司、已激活公司和当前公司。它们回答不同问题：用户可选择哪些公司、本次操作使用哪个范围、哪些依赖上下文的值来自哪家公司。缺少这些信息，验收结果就无法解释某条记录为何可见或被隐藏。

[20.0 访问域求值实现](https://github.com/odoo/odoo/blob/20.0/odoo/addons/base/models/ir_access.py) 从 `env.companies.ids` 取得 `company_ids`，即已激活公司；从 `env.company.id` 取得 `company_id`。记录测试范围时，不要用用户全部公司成员资格代替它。

| 维度 | 示例 | 验收问题 |
| --- | --- | --- |
| 获授权的成员资格 | 用户 7 属于 A 和 B。 | 这个身份能否选择公司 B？ |
| 已激活公司 | 本次调用只激活 A。 | 按公司限定的操作是否排除 B 记录？ |
| 当前公司 | A、B 均激活，当前为 A。 | 操作使用哪家公司的值？ |
| 记录所属公司 | `B-OWN` 属于 B。 | 结果记录是否属于预期公司？ |

[环境实现](https://github.com/odoo/odoo/blob/20.0/odoo/orm/environments.py) 会为普通用户验证所选公司；列表为空时采用回退值；在 `sudo` 模式跳过所述合理性检查。空列表并不表示拒绝全部公司。使用较高权限运行测试，不能证明普通用户隔离成立。

模型将差别直接展示出来：成员资格是 A/B，只激活 A 时，自己的 B 记录被拒绝；激活 A/B 后允许。只有 A 成员资格的用户，在模型中不能激活 B。应保留三个独立用例，而不是统一写成“多公司正常”。

## 简单改写 ACL 为什么可能扩大访问？

一种错误改写会把旧的宽泛模型授权保留为新的宽泛记录授权，再与较窄授权并列。反例用户持有两个组。旧的分层政策拒绝他人记录，新授权的并集却允许读取。这说明错误改写的后果，不是 Odoo 官方转换器的执行结果。

| 阶段 | 示例政策 | A 中他人拥有的记录 |
| --- | --- | --- |
| 旧分层示例 | 模型 ACL 允许读取，再由适用的本人记录规则过滤。 | 拒绝 |
| 简单的新改写 | 宽泛记录授权与本人记录授权组合。 | 允许 |
| 获批目标政策 | 业务负责人仍要求该角色只能访问自己的记录。 | 必须继续拒绝 |

官方 [访问转换源码](https://github.com/odoo/odoo/blob/20.0/odoo/upgrade_code/19.4-00-ir-access.py) 会结合组进行推断，并对宽泛 ACL 组与较窄规则的交互发出警告。警告说明要求复核。我们检查了源码，但没有执行转换器。

将转换器输出和日志与迁移证据一起保存。针对每条警告，确定受影响的实际组组合及操作，再在升级数据库上证明获批结果。即使转换日志没有警告，也仍需回归测试业务政策。

不要据此一律删除宽泛授权，其他角色可能合理需要它。修改共享组前，应比较完整获批矩阵，包括从另一角色继承该组的用户。

## 16 个本地用例观察到了什么？

16 个本地用例均得到预期观察结果。它们展示测试如何区分缺失限制、额外授权和错误公司上下文，也把可见性、取值与关系一致性分开。这些是小型 Python 模型的结果，不是对真实 Odoo 数据库的安全评估。

| 用例 | 预期 | 观察结果 |
| --- | --- | --- |
| 已激活 A 中的本人记录 | 允许 | 允许 |
| 已激活 A 中的他人记录 | 拒绝 | 拒绝 |
| B 已授权但未激活 | 拒绝 B 记录 | 拒绝 |
| B 已授权且已激活 | 允许本人 B 记录 | 允许 |
| 无成员资格却激活 B | 拒绝上下文 | 上下文错误 |
| 增加宽泛组授权 | 他人的 A 记录变为可读 | 允许 |
| 宽泛组加全局公司限制 | 未激活 B 仍被拒绝 | 拒绝 |
| 省略全局公司限制 | 错误配置暴露未激活 B | 允许 |
| 互相矛盾的仅 A、仅 B 全局限制 | 合法 A 记录被阻止 | 拒绝 |
| 无公司归属的共享记录 | 严格政策拒绝；明确共享政策允许 | 拒绝／允许 |
| 只有全局限制，没有组授权 | 拒绝 | 拒绝 |
| 模型中的只读角色 | 允许读；拒绝写和删除 | 允许／拒绝／拒绝 |
| 简单转换旧分层政策 | 旧拒绝变为非预期允许 | 拒绝／允许 |
| 当前公司为 A 或 B 时，B 记录均可见 | 公司值不同：100.00 与 120.00 | 100.00／120.00 |
| 可见 A 记录关联 B 记录 | 访问通过；示例关系检查失败 | 允许／不一致 |
| 已激活公司输入为空 | 回退到成员资格 A/B | B 记录可读 |

下载 [可运行权限模型](/downloads/odoo-20-company-access-migration-tests/permission-model.py) 和 [已记录结果](/downloads/odoo-20-company-access-migration-tests/model-results.json) 。使用 Python 3.10 或更新版本运行：

```
python3 permission-model.py
```

模型将已经展开的实际组集作为输入，不实现组继承、Odoo 域、字段权限、缓存或原生创建与写入钩子。关系检查刻意简化为相等比较。它无法证明真实模块里每个可共享字段或公司依赖字段的行为。

## 原生角色与公司矩阵应包含什么？

原生矩阵需要为每项相关身份、公司上下文和操作确定获批预期，再附上升级系统的证据。将正常允许工作与拒绝访问配对。对禁止写入，除错误信息外还应检查最终状态。菜单缺失的截图无法证明底层操作受到控制。

[建议的原生验收矩阵](/downloads/odoo-20-company-access-migration-tests/native-acceptance.json) 全部从 `NOT_RUN` 开始。示例预期需要批准或替换，并非通用 Odoo 政策。用于发布决策前，应填写实际用户和组、构建版本、入口、记录标识、公司上下文及证据。

| 维度 | 必要对照 | 证据 |
| --- | --- | --- |
| 角色 | 普通所有者与获批的宽范围审核人 | 各身份的实际组集及预期记录集合 |
| 公司范围 | 仅 A、A/B 激活及未获授权的 B 选择 | 准确上下文与目标记录所属公司 |
| 操作 | 允许读写与禁止修改 | 返回记录、结果状态及禁止变化未发生的证据 |
| 入口 | 用户操作与各相关集成或任务 | 实际执行身份及所调用操作 |
| 政策迁移 | 旧获批预期与新目标预期 | 转换器警告、已审查变化和原生观察结果 |
| 业务一致性 | 正确公司值及允许的关联记录 | 取值与关系证据，独立于可见性 |

除正常导航外，也使用直接记录标识测试。为每种入口定义预期观察，例如禁止搜索应不返回其他公司记录，或请求的操作应被拒绝。界面隐藏了多余行，不能成为接受宽泛结果的理由。

破坏性操作只在演练环境中的受控测试记录上执行。加入允许修改的用例，避免“全部阻断”也能通过。 [代理业务状态测试指南](/zh/blog/odoo-ai-agent-business-state-tests/) 将同一证据原则扩展到完整任务，因为看似合理的回复可能掩盖错误记录。

## 访问通过后，为什么还要检查值和关联？

访问通过，表示该身份可按被测政策执行操作。它本身不证明操作使用了目标公司的值，也不证明所选关联兼容。示例可以读取 B 记录，却选中 A 的值；也可以允许访问一条记录，但其新关联未通过独立公司检查。

官方 [多公司指南](https://github.com/odoo/documentation/blob/20.0/content/developer/howtos/company.rst) 将公司依赖值与当前公司关联，并描述通过 `_check_company_auto` 和 `check_company` 单独配置关系检查。应在模块的具体模型和字段上验证这些机制。

示例中两家公司均可读。当前公司选 A 时得到虚构值 100.00，选 B 时得到 120.00。任务若针对 B，成功读出 100.00 仍可能是错误业务结果。应在预期数值旁记录预期公司。

关系测试应选择一个允许链接和一个被禁止的跨公司链接，检查实际赋值操作。可见的公司字段或访问域，不能证明所有自定义关系均被检查。 [自定义 Odoo 模块审计指南](/zh/blog/ai-generated-odoo-module-audit/) 覆盖更广泛的实现审查。

## 哪些证据应阻止或允许发布？

如果非预期身份能访问保护记录、合法用户无法完成必要工作，或无法确认被测公司上下文，就应阻止受影响的迁移范围。只有获批矩阵在目标构建通过、刻意政策变化已签核、未结转换警告已有具体处理决定，才应放行。

将预期矩阵、实际组集快照和准确模块版本与观察结果一起保留。扩大审核角色权限可能合理，但需要明确政策变更。旧拒绝不一定是正确的新规则，旧允许也不一定值得保留。

[发布前 QA 检查表](/zh/software-development-guide/software-qa-checklist-before-launch/) 将这些证据纳入整体上线决定。 [Odoo API 架构指南](/zh/blog/odoo-erp-api-integration-limits-2026/) 继续负责托管和协议边界；改变 API 路径不能替代原生权限测试。

讨论 Wavect 的 [软件质量保障服务](/zh/services/software-quality-assurance/) 时，可准备一个受影响角色、两个公司上下文和自定义模块转换输出。首个有用成果是一份商定的允许／拒绝矩阵，以及对应范围内可复现的原生证据。

## Odoo 20 权限迁移常见问题

### 菜单隐藏就证明底层访问被拒绝了吗？

不能。验收关注身份能访问的记录及操作。应使用受控记录测试正常用户路径和相关直接入口，保存返回数据与最终状态。菜单截图可以记录界面，却不能替代受保护操作确实遵守获批政策的证据。

### allowed_company_ids 为空就能拒绝全部公司吗？

不能。在所检查的 20.0 环境实现中，空列表会回退到用户的公司。应指定明确允许的上下文并验证结果。如果应用需要无访问状态，须将它定义为政策结果并测试，不能依赖空上下文列表来实现。

### 没有公司归属的记录应怎样验收？

先决定哪些记录有意共享，哪些必须归属某家公司。模型分别测试严格公司政策与明确共享政策，结果不同。应为各获批类别准备代表记录及关系赋值。公司字段缺失，不应悄悄变成共享敏感业务数据的指令。

### 继承组和额外组应怎样处理？

审查被测身份的实际组集，包括通过其他角色获得的组。下载模型直接接收这个集合，不计算继承。应测试用户真正持有的组合，特别是受限角色与宽范围审核角色并存。单独测试任一组可能漏掉组合效果。

### 16 个模型用例能证明真实数据库安全吗？

不能。它们只在一个使用标准库的小型 Python 程序中展示特定政策及上下文结果，没有执行 Odoo、解释原生域或测试自定义方法。可用反例改善验收设计，再针对准确升级版本和获批业务政策运行独立的 NOT_RUN 矩阵。

### 服务账户和定时任务有什么不同？

记录每项自动化使用的身份和公司上下文，再测试获批操作。不能用人工管理员浏览替代该执行路径。加入应处理记录和一条不得触碰的受控记录，并检查实际修改。宽泛凭据需要明确业务理由和验收范围。

### 与 Odoo 19 不同就必须阻止发布吗？

未解释的差异应先阻止受影响范围，直到查明原因。有意修正政策可以获批，包括收紧旧的宽泛授权。记录旧预期、新目标规则及批准人，按获批目标比较升级系统，而不是只复制旧行为。

QA 与生产就绪

## 接下来读什么

可靠生产软件所需的测试、审计、维护与加固。

[从这里开始**AI 生成代码的 QA**](/zh/blog/qa-for-ai-generated-code/)

- [README ZIP 恶意软件：审查 AI 工具的实际安装内容](/zh/blog/readme-zip-malware-install-review/)
- [AI 生成的 Odoo 模块：先审业务规则，再谈上线](/zh/blog/ai-generated-odoo-module-audit/)
- [Odoo 迁移验收：逐条核对业务记录与余额](/zh/blog/odoo-migration-acceptance-reconciliation/)
- [Odoo AI 智能体测试：验收实际保存的活动记录](/zh/blog/odoo-ai-agent-business-state-tests/)
- [Odoo 19 升级 20：AI 工作流要重新验收什么？](/zh/blog/odoo-19-20-ai-upgrade-readiness/)

[上一篇文章**Odoo AI 智能体测试：验收实际保存的活动记录**](/zh/blog/odoo-ai-agent-business-state-tests/) [下一篇文章**Odoo 19 升级 20：AI 工作流要重新验收什么？**](/zh/blog/odoo-19-20-ai-upgrade-readiness/)

[**返回**](/zh/blog/overview/)

[![Kevin Riedl](/img/team/kevin.webp)](/zh/team/kevin-riedl/)

[Kevin Riedl](/zh/team/kevin-riedl/) https://linkedin.com/in/wsdt

11 分钟 阅读 · 2026年11月5日 最近审核 2026年11月5日

[**下一篇**](/zh/blog/odoo-email-pdf-quotation-review/)
