odoo13学习---11 访问安全
访问安全
在这一章中,我们将看到如何执行以下内容:
为了简明扼要地说明这一点,本章中的内容对现有模块做了一些小小的补充。
技术要求
本章的技术要求包括使用我们在第四章中创建的模块,创建Odoo附加模块。为了遵循这里的示例,您应该创建并准备使用该模块。
本章中使用的所有代码都可以从以下的GitHub存储库下载:https:// github.com/packtpublishing/odoo-12-develop-cookbookthird - edition/tree/master/chapter11。
查看下面的视频,查看运行中的代码:http://bit.ly/2UCfwlX
创建安全组并将其分配给用户
安全访问在Odoo是通过安全组配置:权限被给予组,然后组被分配给用户。每个功能区域都有由中心应用程序提供的基本安全组。
当附加组件模块扩展现有应用程序时,它们应该向相应的组添加权限,如后面的“添加对模型的安全访问”所示。当附加模块添加现有中央应用程序尚未覆盖的新功能区域时,它们应该添加相应的安全组。通常,我们至少应该具有用户和管理人员角色。
以我们在第4章中介绍的库为例,创建Odoo附加模块,它不适合任何一个Odoo核心应用程序,所以我们将为它添加安全组。
准备
这个配制假设您已经准备好了一个Odoo实例,my_module可用,如第4章“创建Odoo附加模块”所述。
怎么做呢?
要向模块中添加新的访问安全组,请执行以下步骤:
1.确保__manifest__.py附加组件模块清单定义了类别键:
'category': 'Library',
2. 将新的security/groups.xml文件添加到manifest数据键:
'data': [
'security/groups.xml',
'views/library_book.xml',
],
3.为security/library_security_xml的数据记录添加新的XML文件,以空结构开始:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Data records go here -->
</odoo>
4. 在data XML元素中为两个新组添加记录标记
<record id="group_library_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="base.module_category_library"/>
<field name="implied_ids" eval="[(4,ref('base.group_user'))]"/>
</record>
<record id="group_library_librarian" model="res.groups">
<field name="name">Librarians</field>
<field name="category_id" ref="base.module_category_library"/>
<field name="implied_ids" eval="[(4,ref('group_library_user'))]"/>
<field name="users" eval="[(4, ref('base.user_admin'))]"/>
</record>
如果我们升级add-on模块,这两条记录将被加载。为了在UI中查看这些组,您需要激活开发人员模式。然后可以通过设置|Users|Groups菜单选项查看它们。
在Odoo v12中,新添加的模型的默认安全工作方式与以前的模型不同。在v12中,如果您正在添加一个新模型,管理用户不会获得该模型的访问权限。这意味着为该模型添加的菜单和视图对管理用户不可见。为了显示它,您需要为该模型添加访问规则,这在“添加对模型的安全访问”内容中出现。顺便说一下,您可以通过超级用户访问新添加的模型;要了解更多关于它,请参考访问Odoo作为一个超级用户配方从第4章,创建Odoo附加模块。
它是如何工作的…
附加模块按功能领域或主要应用程序组织,如会计和金融、销售或人力资源。它们是由manifest文件中的类别键定义的。
如果一个类别名称还不存在,它将自动创建。为了方便起见,还将为新类别名生成一个小写字母的base.module_category_<category_name_in_manifest> XML ID,用下划线替换空格。这对于将安全组与应用程序类别关联起来非常有用。
在我们的示例中,我们使用了库类别名,它生成了base.module_category_library XML标识符。
按照约定,包含安全相关元素的数据文件应该放在安全子目录中。
您还需要在manifest文件中注册安全文件。文件在模块maniest的数据键中声明的顺序很重要,因为在定义安全组之前,您不能在其他视图或ACL文件中使用安全组的引用。最好将安全数据文件放在列表的顶部,在ACL文件和其他用户界面数据文件之前。
在我们的示例中,我们用<record>创建了组。标记,它将创建res.groups模型的一条记录。res.group模型中最重要的列如下:
name:这是组的显示名称。
category_id:这是对应用程序类别的引用,用于在用户表单中组织组。
implied_ids:这是要从其中继承权限的其他组。
users:这是属于这个组的用户列表。在新的附加组件模块中,我们通常希望admin用户属于应用程序的manager组。
第一个安全组使用implied_ids作为base.group_user组。这是雇员用户组,也是所有后端用户期望共享的基本安全组。
第二个安全组在users字段上设置一个值,将其分配给管理员用户,该用户具有基数。user_admin XML ID。
属于某个安全组的用户将自动属于它的隐含组。如果将Librarians组分配给任何用户,则该用户也将包括在用户组中,因为Librarians组将用户组包含在其implied_ids列中。
另外,安全组授予的访问权限是累积的。如果用户所属的任何组(直接或暗示)授予该权限,则用户具有该权限。
一些安全组在用户表单中显示为选择框,而不是单个复选框。当涉及的组位于相同的应用程序类别中,并且通过implied_ids进行线性关联时,就会发生这种情况。例如,组A有隐含组B,组B有隐含组c。如果一个组通过implied_ids与任何其他组无关,您将看到一个复选框,而不是选择框。
请注意,在前面字段中定义的关系还具有可以在相关模型(如安全组和用户)中编辑的反向关系。
在引用字段(如category_id和implied_ids)上设置值是使用相关记录的XML id和一些特殊语法完成的。该语法将在第7章模块数据中详细解释。
有更多的…
特别的base.group_no_one安全组称为Extra Rights也值得注意。在以前的Odoo版本中,它默认用于隐藏高级功能,只有当技术功能标志被激活时才可见。从版本9.0开始,这一点已经改变了,只要激活Developer模式,这些特性都是可见的。
安全组授予的访问权限只能是累积的。无法拒绝组提供的访问。这意味着用于定制权限的手动创建的组应该从权限少于预期权限(如果有的话)的最近组继承,然后添加所需的所有剩余权限。
组也有这些额外的字段可用:
- Menus (menu_access字段):这些是组可以访问的菜单项
- Views (view_access字段):这些是组可以访问的UI视图
- 访问权限(model_access字段):这是它对模型的访问权限,详细内容在“向模型添加安全访问”内容中
- 规则(rule_groups字段):这些是应用于组的记录级访问规则,详见使用记录规则内容限制记录访问
- 注释(注释字段):这是组的描述或评论文本
添加对模型的安全访问
附加模块添加新模型是很常见的。例如,在第4章“创建Odoo附加模块”中,我们添加了一个新的Library Books模型。在开发过程中很容易错过为新模型创建安全访问权限的过程,并且您可能会发现很难看到已经创建的菜单和视图,因为从Odoo version 12开始,admin用户没有获得对新模型的默认访问权限。为了查看新模型的视图和菜单,您必须添加安全访问控制列表(acl)。
但是,没有ACL的模型将在加载时触发警告日志消息,通知用户缺少ACL定义:
WARNING The model library.book has no access rules, consider adding one example, access_library_book, access_library_book, model_library_book, base.group_user,1,0,0,0
您还可以通过超级用户访问新添加的模型,因为这绕过了所有的安全规则。要了解更多关于这一点,请参考访问Odoo作为一个超级用户配方从第4章,创建Odoo Add-On模块。超级用户特性只对管理员用户可用。因此,为了让非admin用户可以使用新模型,我们需要定义它们的访问控制列表,以便Odoo知道它应该如何访问它们,以及每个用户组应该允许执行哪些操作。
准备
我们将采取我们在第4章创建的模块,创建Odoo附加模块,并添加缺少的acl到它。
怎么做呢?
my_library应该已经包含了models/library_book.py Python文件,该文件创建了library.book模型。现在我们将添加一个数据文件,通过执行以下步骤来描述这个模型的安全访问控制:
1. 编辑__manifest__.py文件以声明一个新的数据文件:
data: [
# ...Security Groups
'security/ir.model.access.csv',
# ...Other data files
]
2. 使用以下代码向模块中添加一个新的security/ir.model.access.csv文件:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
acl_book,library.book_default,model_library_book,base_group_user,1,0,0,0
acl_book_librarian,library.book_librarian,model_library_book,group_library_librarian,1,1,1,1
然后,我们应该升级模块,将这些ACL记录添加到我们的Odoo数据库中。更重要的是,如果我们使用演示用户登录到一个演示数据库,我们应该能够访问Library菜单选项而不会出现任何安全错误。
它是如何工作的…
安全访问控制列表存储在核心ir.model.access模型中。我们只需要添加描述每个用户组预期访问权限的记录。
任何类型的数据文件都可以,但通常的做法是使用CSV文件。该文件可以放在add-on模块目录中的任何位置,但约定是将所有与安全相关的文件放在一个安全子目录中。
我们的内容中的第一步将这个新数据文件添加到manifest中。第二步添加描述安全访问控制规则的文件。CSV文件必须以载入记录的模型命名,因此使用的名称不仅是约定,而且是强制的;详见第7章模块数据。
如果模块还创建了新的安全组,那么它的数据文件应该在acl数据文件之前的清单中声明,因为您可能希望将它们用于acl。它们必须在处理ACL文件时已经创建。
CSV文件中的列如下:
id:这是该规则的XML id内部标识符。模块内的任何唯一名称都可以,但约定是使用access_<model>_<group>。
name:这是访问规则的标题。通常使用access.<model>_<group>名。
model_id:这是模型的XML id。Odoo自动将这种ID分配给model_<name>格式的模型,使用模型的_name下划线代替点。如果模型是在不同的外接程序模块中创建的,则需要包含模块名称的完全限定XML ID。
group_id:id:这是用户组的XML id。如果为空,则适用于所有用户。基本模块提供了一些基本组,比如针对所有员工的base.group_user和针对管理用户的base.group_system。其他应用程序可以添加自己的用户组。
perm_read:前一组的成员可以读取模型记录。它接受两个值:0或1。使用0限制对模型的读访问,使用1提供读访问。
perm_write:前一组的成员可以更新模型记录。它接受两个值:0或1。使用0限制对模型的写访问,使用1提供写访问。
perm_create:前一个组的成员可以添加这个模型的新记录。它接受两个值:0或1。使用0限制对模型的创建访问,使用1提供创建访问。
perm_unlink:前一组的成员可以删除此模型的记录。它接受两个值:0或1。使用0限制对模型的断开链接访问,使用1提供断开链接访问。
我们使用的CSV文件添加了对雇员|雇员标准安全组的只读访问权和对管理|设置组的完全写访问权。
员工用户组base.group_user特别重要,因为Odoo标准应用程序添加的用户组是从它继承的。这意味着,如果我们需要一个能被所有后端用户访问的新模型,而不管他们使用的是什么特定的应用程序,我们应该将该权限添加到员工组中。
生成的acl可以在调试模式下从GUI中查看,导航到Settings|Technical|Security|Access Controls列表,如下图所示:
有些人发现使用这个用户界面来定义acl,然后使用export特性来生成CSV文件更容易。
有更多的…
将此权限授予在创建安全组中定义的Library用户和Library组,并将它们分配给用户内容,这对我们来说是有意义的。如果您遵循了这个方法,那么遵循这个方法是一个很好的练习,使组标识符适应库标识符。
需要注意的是,add-on模块提供的访问列表不应该直接定制,因为它们将在下一次模块升级时重新加载,从而破坏任何可能从GUI完成的定制。
要定制acl,可以使用两种方法。一种是创建新的安全组,从模块提供的安全组继承,并在其上添加额外的权限,但这只允许我们添加权限,而不是删除权限。更灵活的方法是在特定ACL线路上取消选中活动标志以禁用它们。active字段在默认情况下是不可见的,因此我们需要编辑树视图来添加<fieldname="active" />列。我们还可以为附加或替换权限添加新的ACL行。在模块升级时,停用的ACL不会被重新激活,添加的ACL行不会受到影响。
还有一点值得注意,acl只应用于常规模型,不需要为抽象或瞬态模型定义。如果定义了,这些将被忽略,并在服务器日志中触发一条警告消息。
限制对模型中的字段的访问
在某些情况下,我们可能需要更细粒度的访问控制,还可能需要限制对模型中特定字段的访问。
只有特定的安全组可以使用groups属性访问字段。我们将向您展示如何添加对Library Books模型具有有限访问权的字段。
怎么做呢?
要添加访问权限仅限于特定安全组的字段,请执行以下步骤:
1. 编辑模型文件,添加字段:
is_public =fields.Boolean(groups='my_library.group_library_librarian')
private_notes =fields.Text(groups='my_library.group_library_librarian')
2. 在XML文件中编辑视图,添加字段:
<field name="is_public" />
<field name="private_notes" />
就是这样。现在,升级add-on模块以使模型中的更改发生。如果您与一个没有系统配置访问权限的用户登录,比如在一个有演示数据的数据库中进行演示,那么Library Books表单将不会显示该字段。
它是如何工作的…
具有groups属性的字段将被特别处理,以检查用户是否属于该属性中指示的任何安全组。如果一个用户不属于一个特定的组,Odoo将从UI和限制ORM操作该字段删除该字段。
注意,这种安全性不是表面的。该字段不仅隐藏在用户界面中,而且在其他ORM操作(如读和写)中对用户不可用。对于XML-RPC或JSON-RPC调用也是如此。
在业务逻辑或on-change UI事件中使用这些字段时要小心(@api onchange methods);对于无法访问字段的用户,它们可能会引发错误。
一种解决方法是使用特权提升,例如sudo()模型方法或计算字段的compute_sudo字段属性。
groups值是一个字符串,其中包含一个逗号分隔的安全组有效XML id列表。找到特定组的XML ID的最简单方法是激活developer模式并导航到组的表单,在Settings|Users|Groups处,然后从debug菜单中访问View Metadata选项,如下面的屏幕截图所示:
有更多的…
在某些情况下,我们需要一个字段可用或不可用,这取决于特定的条件,比如字段中的值,例如stage_id或state。这通常是在视图级别处理的,使用属性如状态或attrs来根据特定条件动态显示或隐藏字段。有关详细描述,请参阅第10章后端视图。
注意,这些技术仅在用户界面级别工作,并不提供实际的访问安全性。为此,您应该在业务逻辑层中添加签入。添加装饰有@constraints的模型方法,实现预期的特定验证,或者扩展create、write或unlink方法来添加验证逻辑。在第6章基本服务器端业务逻辑中,您可以进一步了解如何做到这一点。
使用记录规则限制记录访问
应用程序的一个常见需求是能够限制哪些记录对特定模型上的每个用户可用。
这是通过使用记录规则实现的。记录规则是在模型上定义的域筛选器表达式,它将被添加到受影响用户所做的每个数据查询中。
作为示例,我们将在Library Books模型中添加一个记录规则,以便员工组中的用户将只能访问公共图书。
这个配制假设您已经准备好了一个实例,my_library可用,如第4章创建Odoo Add-On模块所述。
怎么做呢?
记录规则是使用数据XML文件添加的。为此,请执行以下步骤:
1. 确保manifest data key引用了security/library_security.xml文件:
'data': [
'security/library_security.xml',
# ...
],
2. 我们应该有一个security/library_security.xml数据文件,带有创建安全组的<odoo>部分:
<odoo noupdate="1">
<record model="ir.rule" id="library_book_user_rule">
<field name="name">Library: see only own books</field>
<field name="model_id" ref="model_library_book"/>
<field name="groups" eval="[(4,ref('my_library.group_library_user'))]"/>
<field name="domain_force">
[('is_public', '=', True)]
</field>
</record>
<record model="ir.rule" id="library_book_all_rule">
<field name="name">Library: see all books</field>
<field name="model_id" ref="model_library_book"/>
<field name="groups" eval="[(4,ref('my_library.group_library_librarian'))]"/>
<field name="domain_force">[(1, '=', 1)]</field>
</record>
</odoo>
升级add-on模块将在Odoo实例中加载记录规则。如果您正在使用演示数据,则可以通过默认的演示用户对其进行测试,从而将库用户权限授予演示用户。如果不使用演示数据,可以创建具有库用户权限的新用户。
它是如何工作的…
记录规则只是加载在ir.rule核心模型中的数据记录。虽然添加它们的文件可以位于模块中的任何位置,但约定是在security子目录中。通常有一个同时具有安全组和记录规则的XML文件。
与组不同的是,在标准模块中,记录规则被装载在带有noupdate="1"属性的odoo部分中。这样,那些记录将不会在模块升级时被重新加载,这意味着对它们的手动定制是安全的,并且在以后的升级中仍然有效。
为了与官方模块保持一致,我们还应该将记录规则放在<odoo noupdate="1">节中。
在设置|Technical|Security|Record rules菜单选项中可以看到记录规则,如下截图所示:
下面是本例中使用的最重要的记录规则字段:
Name (Name):规则的描述性标题。
Object(model_id):对应用规则的模型的引用。
Groups(groups):规则应用于的安全组。如果没有指定任何安全组,则认为该规则是全局的,并以不同的方式应用(继续使用此内容以了解有关组的更多信息)。
Domain(domain):用于过滤记录的域表达式。该规则只会应用于这些经过筛选的记录。我们为库用户安全组创建的第一个记录规则。它使用[('is_public','=',True)]域表达式,只选择公开的图书。因此,图书馆用户安全组的用户将只能看到公共图书。记录规则中使用的域表达式使用ORM对象在服务器端运行。因此,点符号可以用于左边的字段(第一个元组元素)。例如,[('country_id.code','=','IN')]域表达式将只显示拥有印度国家的记录。
由于记录规则主要基于当前用户,所以您可以在域的右侧(第三个元组元素)使用用户记录集。因此,如果您想要显示当前用户的公司记录,您可以使用[('conpany_id','=',user.company_id.id)]域。另外,如果您想要显示当前用户创建的记录,您可以使用[('user_id', '=',user.id)]域。
我们希望图书管理员安全小组能够看到所有的图书,不管它们是公共的还是私人的。因为它继承了图书馆用户组,除非我们对它做了一些处理,否则它也将只能看到公共图书。
非全局记录规则使用OR逻辑操作符连接在一起;每个规则都添加访问权限,并且从不删除访问权限。为了让图书管理员能够访问所有图书,我们可以向其添加一个记录规则来添加对所有图书的访问,如下所示:[('is_public','in',[True, False])]。
这里我们选择了不同的方式,使用[(1,'=',1)]特殊规则无条件地提供对所有图书记录的访问。虽然这看起来是多余的,但请记住,否则,可以自定义Library user规则,使一些书籍远离设置用户。域是特殊的,因为域元组的第一个元素必须是字段名;这种情况是不正确的两种情况之一。特殊域[(1,'=',0)]从来都不是真的,但是对于记录规则也不是很有用,因为这种类型的规则用于限制对所有记录的访问。访问列表也可以这样做。
如果您激活了超级用户,记录规则将被忽略。当测试您的记录规则时,确保您使用了另一个用户。
有更多的…
当一个记录规则没有分配给任何安全组时,它被标记为全局的,并且处理方式与其他规则不同。
全局记录规则比组级记录规则的作用更大,可以设置无法覆盖的访问限制。从技术上讲,它们是由AND操作符连接的。在标准模块中,它们用于实现多公司安全访问,以便每个用户只能看到他们公司的数据。
总之,规则的非全局记录规则用OR操作符连接在一起;它们被加在一起,如果任何规则授予了一条记录的访问权,那么它就是可访问的。然后,全局记录规则使用AND操作符向常规记录规则提供的访问权限添加限制。由全局记录规则添加的限制不能被常规记录规则覆盖。
使用安全组激活特性
安全组可以限制某些特性,以便只有属于这些组的用户才能访问它们。安全组还可以继承其他组,因此它们也可以授予它们的权限。
这两个特性结合在一起用来实现Odoo的可用性特性:特性切换。安全组还可以用来为一个Odoo实例中的部分或所有用户启用或禁用特性。
此内容展示了如何向配置设置添加选项,并展示了启用其他特性的两种方法,使用安全组使它们可见,或者通过安装额外的模块来添加它们。
对于第一种情况,我们将使图书发行日期成为一个可选的附加特性,对于第二种情况,作为示例,我们将提供一个选项来安装Notes模块。
准备
这个配制使用my_library,在第4章创建Odoo附加模块中有描述。我们将需要使用安全组,因此您还需要遵循本章中的“添加对模型的安全访问”内容。
在此内容中,一些标识符需要引用附加组件模块的技术名称。我们假设这是my_library。如果您使用不同的名称,请将my_library替换为您的附加组件模块的实际技术名称。
怎么做呢?
要添加配置选项,请遵循以下步骤:
1. 要添加所需的依赖项和新的XML数据文件,像下面这样编辑__manifest__.py文件并检查它是否依赖于base_setup:
{
'name': 'Cookbook code',
'category': 'Library',
'depends': ['base_setup'],
'data': [
'security/ir.model.access.csv',
'security/groups.xml',
'views/library_book.xml',
'views/res_config_settings.xml',
],
}
2. 要添加用于激活特性的新安全组,编辑security/library_book.xml文件,并添加以下记录:
<record id="group_release_dates" model="res.groups">
<field name="name">Library: release date feature</field>
<field name="category_id" ref="base.module_category_hidden" />
</record>
3.要使图书发行日期只在启用这个选项时可见,请在models/library_book.py文件中编辑字段定义:
class LibraryBook(models.Model):
# ...
date_release = fields.Date('Release Date',groups='my_library.group_release_dates')
4. 编辑model /__init__.py文件,为配置设置模型添加一个新的Python文件:
from . import library_book
from . import res_config_settings
5. 要通过添加新选项来扩展核心配置向导,请使用以下代码添加models/res_config_settings.py文件:
# -*- coding: utf-8 -*-
from odoo import models, fields
class ConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
group_release_dates = fields.Boolean("Manage book release dates",group='base.group_user',implied_group='my_library.group_release_dates', )
module_note = fields.Boolean("Install Notes app")
6. 为了让选项在UI中可用,添加views/res_config_settings.xml,它扩展了表单视图:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_general_config_library" model="ir.ui.view">
<field name="name">Configuration: add Library options</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.res_config_settings_view_form" />
<field name="arch" type="xml">
<div id="business_documents" position="before">
<h2>Library</h2>
<div class="row mt16 o_settings_container">
<!-- Release Dates option -->
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="group_release_dates" class="oe_inline"/>
</div>
<div class="o_setting_right_pane">
<label for="group_release_dates"/>
<div class="text-muted">
Enable relase date feature on books
</div>
</div>
</div>
<!-- Release Dates option -->
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="module_note" class="oe_inline"/>
</div>
<div class="o_setting_right_pane">
<label for="module_note"/>
<div class="text-muted">
Install note module
</div>
</div>
</div>
</div>
</div>
</field>
</record>
</odoo>
升级add-on模块之后,两个新的配置选项应该可以在设置|常规设置中使用。屏幕应该是这样的:
它是如何工作的…
核心基础模块提供res.config.settings模型,提供选项激活选项背后的业务逻辑。base_setup 附加模块使用res.config.settings模型提供几个基本配置选项,以便在新数据库中可用。它还使设置|通用设置菜单可用。
base_setup模块将res.config.settings调整到中央管理仪表板,因此我们需要扩展它以添加我们自己的配置设置。如果我们决定为库应用程序创建一个特定的设置表单,我们仍然可以用不同的_name继承res.config.settings模型,然后为新模型提供这些设置的菜单选项和表单视图。我们在第9章“高级服务器端开发技术”的“添加自己的设置选项内容”中已经看到了这种方法。
我们使用了两种不同的方法来激活这些特性:一种方法是启用安全组并使该特性对用户可见,另一种方法是安装提供该特性的附加模块。处理这两种情况的逻辑由基本的res.config.settings模型提供。
内容的第一步将base_setup附加组件模块添加到依赖项中,因为它提供了对我们想要使用的res.config.settings模型的扩展。它还添加了一个额外的XML数据文件,我们将需要该文件向General Settings表单添加新选项。
在第二步中,我们创建一个新的安全组,Library: release date特性。要激活的特性应该仅对该组可见,因此在启用该组之前它将被隐藏。
在我们的示例中,我们希望只有在启用了相应的配置选项时,图书的发布日期才可用。为了实现这一点,我们在字段上使用groups属性,以便它仅对这个安全组可用。我们在模型级别上这样做,以便它自动应用到使用该字段的所有UI视图。
最后,我们扩展了res.config.settings模型以添加新的选项。每个选项都是一个布尔字段,其名称必须以group_或module_开头,这取决于我们希望它做什么。
group_ option字段应该具有implied_group属性,并且应该是一个字符串,其中包含一个以逗号分隔的XML id列表,用于在启用时激活安全组。XML id必须采用完整的形式,包括模块名称、点和标识符名称,如module_name.identifier。
我们还可以提供一个group属性来指定将为哪些安全组启用该特性。如果没有定义组,那么它将对所有基于员工的组启用。因此,相关组将不适用于门户安全组,因为它们不像其他常规安全组那样继承员工基础安全组。
激活背后的机制非常简单:它将group属性中的安全组添加到implied_group中,从而使相关特性对相应的用户可见。
module_ option字段不需要任何附加属性。字段名的其余部分标识激活该选项时要安装的模块。在我们的示例中,module_note将安装note模块。
取消复选框将在没有警告的情况下卸载模块,这可能会导致数据丢失(结果是模型或字段和模块数据将被删除)。为了避免不小心取消复选框,secure_uninstall社区模块(来自https://github.com/oca/server-tools)在卸载附加组件模块之前提示用户输入密码。
此内容的最后一步将其添加到General Settings表单视图中,它位于id="business_documents"的业务文档组之前。我们使用这个id进行视图继承。它用模块名作为ID创建自己的div,这是一种很好的做法,因为扩展my_library的其他模块可以轻松地将它们自己的配置项添加到这个div中。
有更多的…
配置设置也可以使用default_前缀命名字段。当其中一个具有值时,ORM将其设置为全局默认值。设置字段应该有一个default_model属性来标识受影响的模型,而default_前缀后面的字段名称标识将设置默认值的模型字段。
另外,没有上述三个前缀的字段也可以用于其他设置,但是您需要实现逻辑来填充它们的值,使用get_default_ name作为前缀的方法,并在它们的值被编辑时使用set_ name作为前缀的方法。
对于那些想深入了解配置设置细节的人来说,最好的文档是在Odoo的源代码./ Odoo /addons/base/models/res_config.py中,其中有大量的注释和所有细节的解释。
作为超级用户访问记录集
在前面的菜内容中,我们看到了安全技术,例如访问规则、安全组和记录规则。使用这些技术,您可以避免未经授权的访问。然而,有时您会遇到复杂的业务案例,在这些案例中您希望访问或修改记录,即使用户没有访问权。例如,假设公共用户不能访问潜在客户记录,但是通过提交网站表单,用户可以在后端生成潜在客户记录。
使用sudo(),您可以作为超级用户访问记录集。我们已经在第9章高级服务器端开发技术中改变执行操作配方的用户中看到了sudo()。在这里,我们将看到,即使在字段上提供了ACL规则或添加了安全组,仍然可以通过sudo()进行访问。
怎么做呢?
我们将使用与上一个内容相同的my_library模块。我们已经有了一个ALC规则,它为普通用户提供只读读取。我们将添加一个带有安全组的新字段,以便只有图书管理员可以访问它。在此之后,我们将由普通用户修改字段值。遵循以下步骤来实现这一点:
1. 在library.book模型中添加新字段:
report_missing = fields.Text(string="Book is missing",groups='my_library.group_library_librarian')
2. 在表单视图中添加字段:
<field name="report_missing"/>
3.在library.book模型中添加report_missing_book()方法:
def report_missing_book(self):
self.ensure_one()
message = "Book is missing (Reported by: %s)" % self.env.user.name
self.sudo().write({
'report_missing': message
})
4. 在表单视图中添加按钮,从用户界面触发此方法:
<button name="report_missing_book" string="Report Missing Book" type="object"/>
重新启动服务器并更新模块以应用这些更改。
它是如何工作的…
在步骤1和步骤2中,我们在模型和表单视图中添加了一个名为report_missing的新字段。注意,我们将my_library.group_library_librarian组放在Python中的字段上,因此该字段只能由Librarian用户访问。
在下一步中,我们添加了report_missing_book()方法,在该方法的主体中更新了report_missing字段的值。注意,我们在调用write方法之前使用了sudo()。
最后,我们在表单视图中添加了一个按钮,以从用户界面触发该方法。
要测试此实现,需要使用非library用户登录。如果您已经加载了带有演示数据的数据库,那么您可以与演示用户一起登录,然后在图书的表单视图中单击Missing book report按钮。单击该按钮时,将调用report_missing_book()方法,这将在report_missing字段中写入消息,即使用户没有正确的权限。您可以通过管理用户检查字段的值,因为该字段将隐藏在演示用户中。
在单击Report Missing Book按钮时,我们将在report_missing_book()方法中获得当前图书的记录集作为参数self.。在向图书记录集写入值之前,我们使用self.sudo()。这将返回相同的记录集,但使用不同的环境。这个记录集将拥有来自超级用户的环境,并且它将绕过所有访问规则和记录规则。正因为如此,非图书管理员的用户将能够在图书记录中进行书写。甚至模型的日志字段write_uid也将具有超级用户的值。
有更多的…
在使用sudo()时需要格外小心,因为它绕过了所有的访问权限。在多公司环境中,如果您没有正确使用它,它可能会产生问题。如果希望作为另一个用户访问记录集,可以在sudo中传递该用户的ID,比如self_sudo(uid)。这将返回该用户环境的记录集。这样,它就不会绕过所有的访问规则和记录规则,但是您可以执行该用户所允许的所有操作。
基于组隐藏视图元素和菜单
在前面的内容中,我们看到了如何在Python字段定义中使用组参数对某些用户隐藏字段。在用户界面中隐藏字段还有另一种方法:在视图定义中的XML标记上添加安全组。
还可以在菜单上使用安全组对特定用户隐藏它们。
准备
对于此内容,我们将重用上一个菜谱中的my_library附加组件模块。在上一个内容中,我们在<header>标签中添加了一个按钮。我们将通过添加一个groups属性来对一些用户隐藏整个标题。
为book.category模型添加模型、视图和菜单。我们将对用户隐藏类别菜单。参考第5章,应用模型,了解如何添加模型视图和菜单。
怎么做呢?
按照给定的步骤隐藏基于安全组的元素:
1.在<header>上添加一个groups属性,可以对其他用户隐藏它:
...
<header groups="my_library.group_library_user">
...
2. 在<menuitem>图书类别中添加groups属性,只对图书管理员用户显示:
<menuitem name="Book Categories"
id="library_book_category_menu"
parent="library_base_menu"
action="library_book_category_action"
groups="my_library.group_library_librarian"/>
重新启动服务器并更新模块以应用更改。
它是如何工作的…
在第一步中,我们添加了groups="my_library.group_library_user"。这意味着整个标题部分只对图书馆用户和图书管理员可见。没有group_library_user的普通后端用户将看不到标题部分。
在步骤2中,我们在menuitem上添加了groups="my_library.group_library_librarian"属性。这意味着该菜单仅对图书管理员用户可见。您几乎可以在任何地方使用groups属性,包括<field>、<notebook>、<group>、<menuitems>或视图架构中的任何标签。Odoo将隐藏那些元素,如果用户没有该组。您可以在web页面和QWeb报告中使用相同的组属性,这将在第13章自动化、工作流和打印输出和第15章CMS网站开发中介绍。
正如我们在本章超级用户的访问记录集中看到的,我们可以使用Python字段定义中的groups参数对一些用户隐藏字段。请注意,字段上的安全组和视图上的Python安全组之间有很大的区别。Python中的安全组提供了真正的安全性;未经授权的用户甚至不能通过ORM或RPC调用访问字段。然而,视图中的组只是为了提高可用性。在XML文件中通过组隐藏的字段仍然可以通过RPC或ORM访问。

浙公网安备 33010602011771号