限制对数据的访问

重要

本教程是 服务器框架101 教程的扩展。确保您已完成它并使用您构建的 estate 模块作为本教程中练习的基础。

到目前为止,我们主要关注的是实现有用的功能。然而,在大多数业务场景中,*安全*很快就会成为一个问题:目前,

  • 任何员工(即“group_user”代表的内容)都可以创建、读取、更新或删除属性、属性类型或属性标签。

  • 如果安装了“estate_account”,则只有允许与发票交互的代理才能确认销售,因为这是 create an invoice 所必需的。

然而:

  • 我们不希望第三方能够直接访问财产。

  • 并非我们所有的员工都可能是房地产经纪人(例如行政人员、物业经理……),我们不希望非经纪人看到可用的房产。

  • 房地产经纪人不需要或无法决定*可用*哪些房产类型或标签。

  • 房地产经纪人可以拥有*独家*房产,我们不希望一个经纪人能够管理另一经纪人的独家房产。

  • 所有房地产经纪人都应该能够确认他们可以管理的房产的销售,但我们不希望他们能够验证系统中的任何发票或将其标记为已付款。

注解

对于小型企业来说,我们实际上可能可以接受其中的一些或大部分。

由于用户禁用不必要的安全规则比从无到有创建安全规则更容易,因此最好谨慎行事并限制访问:如果必要或方便,用户可以放宽该访问。

团体

其他资料

与此主题相关的文档可以在 the security reference 中找到。

编码指南 记录主数据项的格式和位置。

目标

在本节的最后,

  • 我们可以让员工成为“房地产经纪人”或“房地产经理”。

  • admin 用户是房地产经理。

  • 我们有一名新的“房地产经纪人”员工,无法开具发票或进行管理。

每当我们需要更改时,将个人安全规则附加给员工是不切实际的,因此*组*链接安全规则和用户。它们对应于可以分配给员工的角色。

对于大多数 Odoo 应用程序 1,一个好的基准是拥有 用户*经理*(或管理员)角色:经理可以更改应用程序的配置并监督其整体使用,而用户可以很好地使用应用程序 2

这个基线对我们来说似乎足够了:

  • 房地产经理可以配置系统(管理可用类型和标签)并监督管道中的每个房产。

  • 房地产经纪人可以管理他们所管理的房产,或者不专门由任何经纪人管理的房产。

为了与 Odoo 的数据驱动性质保持一致,组只不过是“res.groups”模型的记录。它们通常是模块 master data 的一部分,在模块的数据文件之一中定义。

作为简单的例子 can be found here

Exercise

  1. 创建“security.xml` file in the appropriate folder and add it to the ``__manifest__.py`”文件。

  2. 如果尚未添加,请添加 'category' field to your __manifest__.py with value Real Estate/Brokerage

  3. 添加一条记录,创建 ID 为“groups_privilege_real_estate`, the name “Real Estate” and the category ``base.module_category_real_estate_brokerage`”的组权限。

  4. 添加一条记录,创建一个 ID 为“estate_group_user`, the name “Agent” and the group privilege ``groups_privilege_real_estate`”的组。

  5. 在其下方,添加一条记录,创建一个 ID 为“estate_group_manager`, the name “Manager” and the group privilege groups_privilege_real_estate. The estate_group_manager group needs to imply ``estate_group_user`”的组。

注解

这个**类别**从哪里来?这是一个*模块类别*。这里我们使用 Odoo 提供的类别 id``base.module_category_real_estate_brokerage`` which was automatically generated by Odoo based on the category set in the __manifest__.py of the module. You can also find here the list of 默认模块类别

小技巧

由于我们修改了数据文件,请记住重新启动 Odoo 并使用“-u estate”更新模块。

如果您转到 Settings ‣ Manage Users 并打开 admin 用户(“Mitchell Admin”),您应该会看到一个新部分:

../../_images/groups.png

将管理员用户设置为*房地产经理*。

Exercise

通过 Web 界面,创建一个仅具有“房地产经纪人”访问权限的新用户。用户不应具有任何发票或管理访问权限。

使用私人选项卡或窗口以新用户身份登录(请记住设置密码),作为房地产经纪人,您应该只能看到房地产应用程序,并且可能还可以看到讨论(聊天)应用程序:

../../_images/agent.png

访问权

其他资料

与此主题相关的文档可以在 访问权 中找到。

目标

在本节的最后,

  • 至少不是房地产经纪人的员工将看不到房地产申请。

  • 房地产经纪人将无法更新房产类型或标签。

访问权限首次在 第 4 章:安全性 - 简介 中引入。

访问权限是一种让用户*通过*组访问模型的方法:将访问权限关联到一个组,然后该组中的所有用户都将具有访问权限。

例如,我们不希望房地产经纪人能够修改可用的房产类型,因此我们不会将该访问权限链接到“用户”组。

访问权限只能授予访问权限,而无法删除访问权限:检查访问权限时,系统会查看与用户关联的*任何*访问权限(通过任何组)是否授予该访问权限。

团体

创造

更新

删除

一个

X

X

X

C

X

具有 A 和 C 组的用户将能够执行任何操作,但删除对象,而具有 B 和 C 组的用户将能够读取和更新它,但不能创建或删除它。

注解

  • 访问权限组可以省略,这意味着 ACL 适用于*每个用户*,这是一个有用但有风险的后备方案,因为根据安装的应用程序,它甚至可以授予非用户访问模型的权限。

  • 如果用户没有访问权限,则不会授予他们访问权限(默认拒绝)。

  • 如果菜单项指向用户无权访问的模型,并且没有用户可以看到的子菜单,则不会显示该菜单。

Exercise

将访问权限文件更新为:

  • 向您的房地产经理组授予对所有对象的完全访问权限。

  • 只授予代理(房地产用户)对类型和标签的读取权限。

  • 赋予任何人删除属性的权利。

  • 检查您的代理用户是否无法更改类型或标签或删除属性,但他们可以以其他方式创建或更新属性。

警告

请记住为您的“ir.model.access”记录提供不同的 xid,否则它们将相互覆盖。

由于“演示”用户不是房地产经纪人或经理,他们甚至不应该能够看到房地产申请。使用私人选项卡或窗口来检查这一点(“演示”用户的密码为“demo”)。

记录规则

其他资料

与此主题相关的文档可以在 记录规则 中找到。

目标

在本节结束时,代理将无法看到其同事专有的属性;但管理者仍然能够看到一切。

访问权限可以授予对整个模型的访问权限,但通常我们需要更具体:虽然代理通常可以与属性交互,但我们可能不希望他们更新甚至看到由其同事之一管理的属性。

记录*规则*提供了这种精确性:它们可以授予或拒绝对单个记录的访问:

<record id="rule_id" model="ir.rule">
    <field name="name">A description of the rule's role</field>
    <field name="model_id" ref="model_to_manage"/>
    <field name="perm_read" eval="False"/>
    <field name="groups" eval="[Command.link(ref('base.group_user'))]"/>
    <field name="domain_force">[
        '|', ('user_id', '=', user.id),
             ('user_id', '=', False)
    ]</field>
</record>

搜索域 是管理访问的方式:如果记录通过,则授予访问权限,否则访问将被拒绝。

小技巧

由于规则往往相当复杂并且不是批量创建的,因此它们通常以 XML 格式而不是用于访问权限的 CSV 格式创建。

上面的规则:

  • 仅适用于“创建”、“更新”(写入)和“删除”(取消链接)操作:这里我们希望每个员工都能够看到其他用户的记录,但只有作者/受让人可以更新记录。

  • non-global 所以我们可以提供额外的规则,例如经理。

  • 如果在记录上设置(例如创建或分配)当前用户(user.id),或者记录根本没有关联的用户,则允许该操作。

注解

如果没有定义或应用于模型和操作的规则,则允许该操作(默认允许),如果访问权限设置不正确(过于宽松),这可能会产生奇怪的效果。

Exercise

定义一条规则,限制代理只能查看或修改没有销售人员或他们是销售人员的房产。

您可能想要创建第二个房地产经纪人用户,或者创建销售人员担任经理或其他用户的一些房产。

确认您的房地产经理仍然可以查看所有房产。如果没有,为什么不呢?记住:

estate_group_manager group needs to imply estate_group_user

安全覆盖

绕过安全性

目标

在本节结束时,代理商应该能够确认房产销售,而无需发票访问权限。

如果您尝试以房地产经纪人的身份将房产标记为“已出售”,您应该会收到访问错误:

../../_images/error1.png

发生这种情况是因为 estate_account` 在此过程中尝试创建发票,但创建发票需要所有发票管理的权限。

我们希望代理商能够在没有完全发票访问权限的情况下确认销售,这意味着我们需要“绕过”Odoo 的正常安全检查才能创建发票,“尽管”当前用户无权这样做。

有两种主要方法可以绕过 Odoo 中的现有安全检查,无论是故意还是作为副作用:

  • sudo() 方法将在“sudo 模式”下创建一个新的记录集,这会忽略所有访问权限和记录规则(尽管硬编码的组和用户检查可能仍然适用)。

  • 执行原始 SQL 查询将绕过访问权限和记录规则,这是绕过 ORM 本身的副作用。

Exercise

更新“estate_account”以在创建发票时绕过访问权限和规则。

危险

通常应避免使用这些功能,并且仅在检查当前用户和操作应能够绕过正常访问权限验证后才极其谨慎地使用这些功能。

在此类模式下执行的操作还应尽可能少地依赖用户输入,并应最大程度地对其进行验证。

以编程方式检查安全性

目标

在本节末尾,无论“estate”如何更改,发票的创建都应该能够适应安全问题。

在 Odoo 中,仅在*通过 ORM* 执行数据访问时检查访问权限和记录规则,例如通过 ORM 方法创建、读取、搜索、写入或取消链接记录。其他方法*不一定*检查任何类型的访问权限。

在上一节中,我们在“action_sold”中创建发票时绕过了记录规则。任何用户都可以访问此绕过,无需检查任何访问权限:

  • 在创建发票之前将打印添加到“action_sold` in ``estate_account`”(因为创建发票会访问该属性,因此会触发 ACL 检查)例如:

    print(" reached ".center(100, '='))
    

您应该在 Odoo 日志中看到“reached”,后面跟着一个访问错误。

危险

仅仅因为您已经使用 Python 代码并不意味着已经或将会检查任何访问权限或规则。

当前*通过访问“`self`` as well as calling ``super()`` (which does the same and *updates ``self`”上的数据来隐式检查访问,触发访问错误并取消“取消创建”我们的发票的交易。

*但是*如果将来这种情况发生变化,或者我们向该方法添加副作用(例如,向政府机构报告销售情况),或者在“estate”中引入错误,…非代理可能会触发他们不应访问的操作。

因此,当执行非 CRUD 操作,或合法绕过 ORM 或安全性,或触发其他副作用时,执行“显式安全检查”极其重要。

可以通过以下方式执行显式安全检查:

  • 检查当前用户是谁(self.env.user)并将其与特定模型或记录进行匹配。

  • 检查当前用户是否具有硬编码的特定组以允许或拒绝操作(self.env.user.has_group)。

  • 在记录集上调用“check_access(operations)”,这将验证当前用户是否有权对该集的*每个*记录执行操作。作为一种特殊情况,当记录集为空时,它会验证当前用户是否具有对模型执行操作的某些访问权限。

Exercise

在创建发票之前,请使用“check_access”确保当前用户可以更新发票所属的属性。

重新运行旁路脚本,检查打印之前是否出现错误。

多公司安全

其他资料

多公司指南 了解多公司设施的总体概述,尤其是 multi-company security rules

一般规则的文档可以再次在 记录规则 中找到。

目标

在本节末尾,代理只能访问其代理机构(或多个代理机构)的财产。

出于某种原因,我们可能需要作为多家公司来管理我们的房地产业务,例如我们可能拥有很大程度上自主的机构、特许经营机构或多个品牌(可能是通过收购其他房地产企业而获得的),这些品牌在法律上或财务上彼此保持独立。

Odoo 可用于管理同一系统内的多个公司,但实际处理取决于各个模块:Odoo 本身提供了管理公司相关字段和“多公司规则”问题的工具,这是我们要关心的。

我们希望不同的机构彼此“孤立”,属性属于给定机构,而用户(无论是代理还是经理)只能看到与其代理相关的属性。

和以前一样,因为这是基于重要的记录,所以用户放宽规则比收紧规则更容易,因此默认使用相对更强的安全模型是有意义的。

多公司规则只是基于“company_ids` or ``company_id`”字段的记录规则:

  • company_ids 是当前用户有权访问的所有公司

  • company_id 是当前活跃的公司(用户当前正在工作的公司)。

多公司规则“通常”将使用前者,即检查记录是否与用户有权访问的“一个”公司关联:

<record model="ir.rule" id="hr_appraisal_plan_comp_rule">
    <field name="name">Appraisal Plan multi-company</field>
    <field name="model_id" ref="model_hr_appraisal_plan"/>
    <field name="domain_force">[
        '|', ('company_id', '=', False),
             ('company_id', 'in', company_ids)
    ]</field>
</record>

危险

多公司规则通常为 global,否则存在附加规则允许绕过多公司规则的高风险。

Exercise

  • 添加``company_id`` field to estate.property,它应该是必需的(我们不想要无代理属性),并且应该默认为当前用户的当前公司。

  • 创建一家新公司,并在该公司中任命一名新的房地产经纪人。

  • 经理应该是两家公司的成员。

  • 旧代理人只能是旧公司的成员。

  • 在每个公司中创建一些属性(使用公司选择器作为经理或使用代理)。取消设置默认推销员以避免触发*该*规则。

  • 所有代理商都可以看到所有公司,这是不可取的,添加记录规则限制这种行为。

警告

当您更改模块的模型或数据时,请记住“--update”您的模块

可见性!=安全性

目标

在本节结束时,房地产经纪人不应看到房地产应用程序的“设置”菜单,但仍应能够设置房产类型或标签。

特定的 Odoo 模型可以直接与组(或公司或用户)关联。在使用此关联之前,弄清楚它是*安全*还是*可见性*功能非常重要:

  • 可见性 功能意味着用户仍然可以访问模型或记录,否则,无论是通过界面的其他部分还是通过 performing operations remotely using RPC,在某些情况下,事物可能在 Web 界面中不可见。

  • *安全*功能意味着用户无法访问记录、字段或操作。

以下是一些示例:

Exercise

房地产经纪人无法添加房产类型或标签,但可以在创建房产表单视图时查看其选项。

设置菜单只会给他们的界面增加噪音,使其只有经理才能看到。

尽管无法再访问“属性类型”和“属性标签”菜单,代理仍然可以访问底层对象,因为他们仍然可以选择要在其属性上设置的标签或类型。

1

Odoo 应用程序是一组覆盖某个业务领域或领域的相关模块,通常由一个基本模块和在此基础上的许多扩展组成,以添加可选或特定功能,或链接到其他业务领域。

2

对于大多数或每个员工都会使用的应用程序,“应用程序用户”角色可能会被取消,并将其能力直接授予所有员工,例如一般来说,所有员工都可以提交费用或请假。