odoo 許可權管理學習總結

授客發表於2023-03-13

環境

odoo-14.0.post20221212.tar

base_user_role-12.0.2.1.2.zip

下載地址:

https://apps.odoo.com/apps/modules/12.0/base_user_role/

許可權管理

簡介

為了更好的熟悉許可權,我們先來了解下使用者,odoo中的使用者分為三類:

  • 內部使用者(Internal User): 企業內部的使用者,擁有對系統內部的訪問許可權,也就是說有odoo後端的訪問許可權。
  • 門戶使用者(Portal): 非企業內部使用者,通常為業務合作伙伴使用者,擁有有限的資源訪問許可權。
  • 公共使用者(Public): 面向公眾的許可權,可以理解為遊客許可權。

提示:管理員登入系統,啟用開發者模式,即可在設定-使用者詳情頁對使用者型別進行編輯(Settings -> Users & Companies -> Users)

以上三類使用者的資訊都存在res_userres_partner表中,那麼在odoo中如何區分使用者型別以及如何做許可權控制的呢?

為了解決上述問題,odoo採用了使用者組機制。將使用者劃分為不同的組(一個使用者可以歸屬多個使用者組,一個使用者組也可以擁有多個使用者),然後給組分配許可權,從而實現使用者許可權的管控及使用者型別識別。

以上三種使用者分別歸屬以下使用者組:

  • 內部使用者:base.group_user
  • 門戶使用者:base.group_portal
  • 公共使用者:base.group_public

odoo也支援自定義使用者組(Settings -> Users & Companies -> Groups),併為使用者分配不同的使用者組,及設定相關許可權(選單許可權,檢視許可權,訪問許可權,記錄規則)

此外,為了更方便的管理使用者組,odoo還支援對使用者組(group)進行分類:將多個使用者組劃分為一個使用者組分類(category)。

  • 使用者組和使用者組分類:一個使用者組分類可以擁有多個使用者組,一個使用者組僅歸屬一個使用者組分類,屬於1對多的關係。
  • 使用者組和使用者組的關係:使用者組可以被使用者組繼承(偽繼承),當繼承某個使用者組時,本組使用者也會自動加入繼承的使用者組。如果一個使用者屬於多個使用者組,那麼該使用者許可權為使用者組許可權的並集,因此設計使用者組許可權時一定要考慮好組與組之間許可權是否會發生衝突。

定義使用者組(許可權組)

示例:xml資料檔案的方式定義選單許可權使用者組

<odoo>
    <data noupdate="1">
         <record id="estate_property_menu_groups" model="ir.module.category"><!-- id:供程式碼或者xml中引用,model:odoo的category模型-->         
             <field name="name">[房地產]模組選單許可權</field><!--使用者組分類名稱--> 
             <field name="sequence">1</field><!--組分類顯示順序、優先順序-->
         </record>

         <!--########################
         [房地產]模組選單
         ########################-->
        <record id="group_estate_property_root_menu" model="res.groups">
            <field name="name">Real Estate</field><!--使用者組名稱,闡明組的角色/目的-->
            <field name="category_id" ref="estate_property_menu_groups"/><!--指定使用者組所屬組分類-->
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/><!--定義使用者組繼承自哪些組,也就是說該使用者組也擁有這些繼承組的許可權-->
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/><!--為使用者組新增使用者 base.user_root root使用者 -->   
        </record>
    </data> 
</odoo>

說明:

noupdate:如果資料檔案的內容預期只應用一次(只載入一次,安裝或者更新模組時),則可以將noupdate設定為1。如果檔案中的部分資料需要應用一次,則可以將檔案的這部分放在<data-noupdate="1">中,如下:

<odoo>
    <data noupdate="1">
        <!-- Only loaded when installing the module (odoo-bin -i module) -->
        <operation/>
    </data>
    <!-- (Re)Loaded at install and update (odoo-bin -i/-u) -->
    <operation/>
</odoo>

參考連線:https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/data.html?highlight=noupdate

base.user_adminadmin使用者(ID為2的使用者,使用者資料定義在odoo\addons\base\data\res_users_data.xml

base.user_root__system__使用者(ID為1的使用者,technical admin )

category定義相關資料儲存在ir_module_category表中

新增的group,可以在Settings -> Users & Groups -> Groups介面看到,組定義相關資料儲存在res_groups表中

eval語法說明

  • (0, 0, values) 從提供的valueS字典建立新記錄,形如(0, 0, {'author': user_root.id, 'body': 'one'})
  • (2, ID, values) 使用values字典中的值更新id值=ID的現有記錄
  • (2, ID) 刪除id=ID這條記錄(呼叫unlink方法,刪除資料及整個主從資料連結關係)
  • (3, ID) 刪除主從資料的連結關係但是不刪除這個記錄
  • (4, ID) 為id=ID的資料新增主從連結關係
  • (5) 去除所有的連結關係,也就是迴圈所有的從資料且呼叫(3,ID)
  • (6, 0, [IDs]) 用IDs中的記錄替換原來連結的記錄(相當於先執行(5)再迴圈執行(4, ID)

擴充:

odoo中有個特殊的組base.group_no_one,需要開啟Debug模式才可獲取該組許可權。可以利用該特性實現隱藏物件需求,比如針對一些常規下不需要顯示的特殊欄位,為其設定屬性groups = "base.group_no_one",可以實現在非Debug模式下隱藏欄位在檢視中的顯示。

選單訪問許可權

應用例項

estate/security/security_estate_property_menu_groups.xml

<odoo>
    <data noupdate="1">
         <record id="estate_property_menu_groups" model="ir.module.category">
             <field name="name">[房地產]模組選單許可權</field>
             <field name="sequence">1</field>
         </record>

         <!--########################
         [房地產]模組選單
         ########################-->
        <record id="group_estate_property_root_menu" model="res.groups">
            <field name="name">Real Estate</field>
            <field name="category_id" ref="estate_property_menu_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_advertisements_menu" model="res.groups">
            <field name="name">Real Estate -> Advertisements</field>
            <field name="category_id" ref="estate_property_menu_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_advertisements_properties_menu" model="res.groups">
            <field name="name">Real Estate -> Advertisements -> Properties</field>
            <field name="category_id" ref="estate_property_menu_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>
</odoo>

estate/__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':[
        'security/security_estate_property_menu_groups.xml',
        //...略
    ]
}
選單配置

views/estate_menus.xml

<?xml version="1.0"?>
<odoo>
    <menuitem id="test_menu_root" name="Real Estate" web_icon="estate,static/img/icon.png"
    groups="group_estate_property_root_menu">
        <menuitem id="test_first_level_menu" name="Advertisements" groups="group_estate_property_advertisements_menu">
            <menuitem id="estate_property_menu_action" action="link_estate_property_action" groups="group_estate_property_advertisements_properties_menu"/>
            <!--略-->
        </menuitem>
        <!--略-->
    </menuitem>
</odoo>

檢視效果

注意:

  1. 實踐時發現,透過介面點選,訪問一些選單介面時,會在選單訪問URL(參見選單訪問自動生成的URL)中自動新增model,view_type等引數,也就是說會自動訪問模組相關模型,如果此時沒有對應模型的訪問許可權(至少需要 read許可權),那麼即便擁有對應選單的訪問許可權,介面上也看不到對應的選單,筆者嘗試過在瀏覽器中直接透過選單連結(形如二級導航選單http://localhost:8888/web#action=85&cids=1&menu_id=127)訪問選單,發現介面上不會顯示任何選單。

    選單訪問自動生成的URL

    http://localhost:8888/web#action=85&model=estate.property&view_type=kanban&cids=1&menu_id=70
    
  2. 透過上述方式實現的選單訪問許可權控制,實際是透過控制是否隱藏選單實現的,也就說,如果知道未授權選單ID,還是可以透過選單ID拼接選單URL進行未授權訪問。

模型訪問許可權(Access Rights,表級別)

當模型中沒有定義任何訪問許可權時,odoo會認為沒有任何使用者可以訪問資料,並在日誌中列印:

2022-12-14 09:01:38,994 32508 WARNING odoo odoo.modules.loading: The model estate.property has no access rules, consider adding one. E.g. access_estate_property,access_estate_property,model_estate_property,base.group_user,1,0,0,0 

訪問許可權被定義為ir.model.access 模型記錄。每個訪問許可權關聯一個模型,一個group(針對全域性訪問,沒有組) 和一系列許可權:create, read, writeunlink(等同於delete)。這些訪問許可權通常定義在security/ir.model.access.csv檔案中。

test.model模型訪問許可權配置示例

id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_test_model,access_test_model,model_test_model,base.group_user,1,0,0,0
  • id 自定義外部標識,模組中保持唯一,一般命名為 access_模型名稱_使用者組名稱
  • name 自定義ir.model.access的名稱,一般命名沿用id取值即可
  • model_id/idmodel_id:id 代指需要應用訪問許可權的模型。標準格式為 model_<model_name>,其中, <model_name>為模組中_name 替換._後的_name 的值
  • group_id/idgroup_id:id 代指需應用訪問許可權的組,即指定哪個組擁有如下訪問許可權,如果指定組不是在當前模組中定義的組,需要指定模組名稱,形如module_name.groupName。組名一般命名為group_模型名稱_許可權,形如group_estate_property_read 。如果 group_id為空,則意味著授權給所有使用者(非僱員(employees) ,比如 portal 或者public使用者).
  • perm_read,perm_write,perm_create,perm_unlink: 分別代表create(建立), read(只讀/查詢), write (編輯/更新)和unlink(刪除)許可權,1表示有訪問許可權,0-表示無許可權

具體到實際應用時,為了更靈活的許可權管理,一般會為模型的增刪改查操作分別定義許可權。

授權給使用者的模型訪問許可權,可透過點選Settings -> Users & Groups -> Users使用者詳情頁Access Rights按鈕檢視。

應用例項

xml資料檔案的方式定義房地產模型訪問許可權

estate/security/security_estate_property_model_groups.xml

<odoo>
    <data noupdate="1">
         <record id="estate_property_model_groups" model="ir.module.category">
             <field name="name">[房地產]模型許可權</field>
             <field name="sequence">1</field>
         </record>


         <!--########################
         [房地產]模型
         ########################-->
        <!-- [房地產]模型 增刪改查 -->
        <record id="group_estate_property_read" model="res.groups">
            <field name="name">[房地產]模型 只讀</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_write" model="res.groups">
            <field name="name">[房地產]模型 更新</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_create" model="res.groups">
            <field name="name">[房地產]模型 建立</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_delete" model="res.groups">
            <field name="name">[房地產]模型 刪除</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>
</odoo>

estate/security/ir.model.access.csv

id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_estate_property_group_estate_property_read,access_estate_property_group_estate_property_read,model_estate_property,group_estate_property_read,1,0,0,0
access_estate_property_group_estate_property_write,access_estate_property_group_estate_property_write,model_estate_property,group_estate_property_write,1,1,0,0
access_estate_property_group_estate_property_create,access_estate_property_group_estate_property_create,model_estate_property,group_estate_property_create,1,0,1,0
access_estate_property_group_estate_property_delete,access_estate_property_group_estate_property_delete,model_estate_property,group_estate_property_delete,1,0,0,1

estate/__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':[
        'security/security_estate_property_menu_groups.xml',
        'security/security_estate_property_model_groups.xml',
        'security/ir.model.access.csv', 
        //...略
    ]
}
檢視效果

開啟使用者編輯介面

記錄規則(Record Rules,記錄級別)

記錄規則是允許某個操作必須滿足的條件。記錄規則按照訪問許可權逐條記錄評估。

預設允許的記錄規則:如果授予模型訪問許可權(Access Rights),並且沒有規則適用於使用者的操作和模型,則授予訪問許可權

記錄規則儲存在ir.rule模型表裡,我們透過管理ir_rule表中的記錄,即可控制記錄的訪問許可權

定義規則

示例:xml資料檔案的方式定義房地產模型記錄訪問規則

<odoo>
    <data noupdate="0">
        <!--########################
        [房地產]模型記錄規則
        ########################-->
        <record id="estate_property_record_read_rule" model="ir.rule"><!--id:外部規則id,供程式碼或者xml中引用 -->
            <field name="name">[房地產]模型記錄規則</field>
            <field name="model_id" ref="model_estate_property"/>
            <field name="domain_force">[('create_uid', '=', user.id)]</field><!--僅顯示使用者自己建立的記錄-->
            <field name="groups" eval="[(4, ref('group_estate_property_record_read'))]"/>
            <!--操作許可權(僅作用於經domain_force濾後的記錄)-->
            <field name="perm_read" eval="1"/>
            <field name="perm_write" eval="1"/>
            <field name="perm_create" eval="1"/>
            <field name="perm_unlink" eval="1"/>
        </record>
    </data>
</odoo>
  • name

    規則名稱

  • model_id

    需要應用規則的模型,標準格式為 model_<model_name>,其中, <model_name>為模組中_name 替換._後值

  • groups

    指定規則需要作用、不作用於哪些組(res.groups)。可以指定多個組。如果未指定組,規則為gobal規則。規則與組的關聯關係存在rule_group_rel表中

  • global

    根據“groups”計算,提供了對規則是否全域性狀態的輕鬆訪問。eval="True"eval="1"則表示全域性規則,eval="False"eval="0"則表示非全域性規則

  • domain_force

    指定為 domain的謂詞,如果該domain與記錄匹配,則規則允許所選操作,否則禁止。可以簡單的理解為指定過濾條件,使用者只能訪問符合本過濾條件的記錄,配置為 [(1,'=',1)]則表示匹配所有記錄。domain是一個可以使用以下變數的python表示式:

    • time

      Python的 time 模組

    • user

      以單例記錄集(singleton recordset)表示的當前使用者

    • company_id

      當前使用者,當前所選的公司的公司id(非記錄集)。

    • company_ids

      當前使用者可以訪問的公司ID列表(非記錄集)。 檢視Security rules 獲取更多詳細資訊。

官方文件:

The perm_method have completely different semantics than for ir.model.access: for rules, they specify which operation the rules applies for. If an operation is not selected, then the rule is not checked for it, as if the rule did not exist.

All operations are selected by default

譯文:

perm_method 具有與 ir.model.access完全不同的語義:對於規則,它們指定規則需要應用的操作。如果(規則)未選擇某個操作,則不會為該操作檢查規則,就像該規則不存在一樣。

規則預設適用所有操作。

筆者實踐發現:

  • 如果建立了規則,但是沒有授權給使用者,那對於該使用者來說,該規則不起作用,就像該規則不存在一樣
  • perm_methodeval值不能同時為"False""0",否則會違反 ir_rule表的檢查約束ir_rule_no_access_rightsCHECK (perm_read!=False or perm_write!=False or perm_create!=False or perm_unlink!=False)
  • 將任意一個perm_method設定為eval="True"eval="1" ,並將規則授權給使用者,規則生效,所以我個人理解,目前記錄規則,就是用於過濾記錄的,透過domain_force控制哪些記錄可以顯示給使用者

規則預設適用所有操作。

  • perm_create

  • ``perm_read`

  • perm_write

  • perm_unlink

  • 授權給使用者的記錄訪問規則,可透過點選Settings -> Users & Groups -> Users使用者詳情頁Record Rules按鈕檢視。

全域性規則(Global rules) VS 組規則(group rules)

全域性規則和組規則在組成和組合方式上存在很大差異:

  • 全域性規則和全域性規則之間取交集,如果兩個全域性規則都生效,則必須滿足兩者才能授予訪問許可權,這意味著新增全域性規則總是會進一步限制訪問。
  • 組規則和組規則之間取並集,如果兩個組規則都生效,則滿足其中之一就可以授予訪問許可權。這意味著新增組規則可以擴充套件訪問,但不能超出全域性規則定義的範圍。
  • 全域性規則集和組規則集之間取交集,這意味著新增到給定全域性規則集的第一個組規則將限制訪問。

危險提示

建立多個全域性規則是有風險的,因為可能建立不重疊的規則集,這將刪除所有訪問許可權

應用例項

estate/security/security_estate_property_model_groups.xml,新增group_estate_property_record_query

<odoo>
    <data noupdate="1">
         <record id="estate_property_model_groups" model="ir.module.category">
             <field name="name">[房地產]模型許可權</field>
             <field name="sequence">1</field>
         </record>


         <!--########################
         [房地產]模型
         ########################-->
        <!-- [房地產]模型 增刪改查 -->
        <record id="group_estate_property_read" model="res.groups">
            <field name="name">[房地產]模型 只讀</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_write" model="res.groups">
            <field name="name">[房地產]模型 更新</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_create" model="res.groups">
            <field name="name">[房地產]模型 建立</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>

        <record id="group_estate_property_delete" model="res.groups">
            <field name="name">[房地產]模型 刪除</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>
  
    <data noupdate="0">
        <!--########################
         [房地產]模型記錄
         ########################-->
        <record id="group_estate_property_record_query" model="res.groups">
            <field name="name">[房地產]模型記錄 查詢</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>       
    </data>
</odoo>

estate/security/security_estate_property_model_record_rules.xml

<odoo>
    <data noupdate="0">
        <!--########################
        [房地產]模型記錄規則
        ########################-->
        <record id="estate_property_record_read_rule" model="ir.rule">
            <field name="name">[房地產]模型記錄規則</field>
            <field name="model_id" ref="model_estate_property"/>
            <field name="domain_force">[('create_uid', '=', user.id)]</field>
            <field name="groups" eval="[(4, ref('group_estate_property_record_read'))]"/>
            <field name="perm_read" eval="1"/>
            <field name="perm_write" eval="1"/>
            <field name="perm_create" eval="1"/>
            <field name="perm_unlink" eval="1"/>
        </record>
    </data>
</odoo>

estate/__manifest__.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
{
    'name': 'estate',
    'depends': ['base'],
    'data':[        
        'security/security_estate_property_menu_groups.xml',
        'security/security_estate_property_model_groups.xml',
        'security/security_estate_property_model_record_rules.xml',
        'security/ir.model.access.csv',
        //...略
    ]
}

檢視效果

參考連線:https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/security.html#record-rules

欄位許可權(Field Access,欄位級別)

ORM欄位可以具有提供組列表的groups屬性(值為逗號分隔的組XML ID列表,如groups='base.group_user,base.group_system'注意:groups屬性值格式:moduleName.groupName,其中moduleNamegroupName組所在模組名稱,必不可少

如果當前使用者不在列出的組中,他將無權訪問該欄位:

  • 將自動從請求的檢視中刪除受限制的欄位
  • fields_get()響應中刪除受限制的欄位

嘗試(顯式的)讀取或寫入受限欄位會導致訪問錯誤

修改estate\security\security_estate_property_model_groups.xml,新增group_estate_property_selling_price_field

    <data noupdate="0">
        <!--########################
         [房地產]模型記錄
         ########################-->
        <record id="group_estate_property_selling_price_field" model="res.groups">
            <field name="name">[房地產]模型 售價欄位</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
        <record id="group_estate_property_record_query" model="res.groups">
            <field name="name">[房地產]模型記錄 查詢</field>
            <field name="category_id" ref="estate_property_model_groups"/>
            <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
            <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
        </record>
    </data>

檢視效果

修改estate\views\estate_property_views.xml檢視selling_price欄位,新增groups屬性

<field name="selling_price" string="Selling Price" groups="estate.group_estate_property_selling_price_field"/>

驗證,發現介面上,未授權上述框選許可權的使用者已經看不到上述欄位了

注意:透過為當前檢視中目標欄位新增groups屬性實現的許可權控制僅作用於當前檢視,如果希望當前檢視模型(Model)的所有檢視中,對該欄位實現統一的許可權控制話,需要在模型定義中,為目標欄位新增groups屬性,如下

selling_price = fields.Float('selling price', digits=(8, 2), readonly=True, copy=False, groups="estate.group_estate_property_selling_price_field")

參考連線:https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/security.html#field-access

擴充套件:在頁面從資料庫載入檢視時,會透過load_view介面,會呼叫fields_view_get方法,可以重寫此方法以控制xml顯示的效果(參考網路資料,未實踐驗證)

按鈕許可權(按鈕級別)

類似欄位許可權控制,僅需在在對應檢視中,為目標按鈕<button>元素,新增groups屬性即可。

角色定義

新增並安裝base_user_role模組

base_user_role模組的作用可以簡單理解為,按自定義維度將所需許可權組組合在一起,組成角色,實現批次授權的功能。

解壓下載的base_user_role-12.0.2.1.2.zip檔案,對解壓後的部分檔案做如下修改:

base_user_role\models\user.pybase_user_role\models\role.py

去除上述兩個檔案中的所有@api.multi修飾符,解決安裝報錯問題:

AttributeError: module 'odoo.api' has no attribute 'multi'

說明:Odoo 13.0開始,移除multimulti作為預設實現。

base_user_role/views/role.xml

修改

<record model="ir.actions.act_window" id="action_res_users_role_tree">
    <field name="name">Roles</field>
    <field name="type">ir.actions.act_window</field>
    <field name="res_model">res.users.role</field>
    <field name="view_type">form</field>
    <field name="view_id" ref="view_res_users_role_tree"/>
</record>

<record model="ir.actions.act_window" id="action_res_users_role_tree">
    <field name="name">Roles</field>
    <field name="type">ir.actions.act_window</field>
    <field name="res_model">res.users.role</field>
    <field name="view_mode">form</field>
    <field name="view_id" ref="view_res_users_role_tree"/>
</record>

解決安裝報錯問題:

odoo.tools.convert.ParseError: while parsing file:/d:/codepojects/odoo14/custom/base_user_role/views/role.xml:63, near

然後,將解壓目錄下base_user_role整個資料夾複製odoo14\custom目錄下,最後,重啟服務並安裝該模組。

安裝成功後,Settings -> Users & Companies選單下,將新增Roles子選單(筆者實踐發現無法透過該頁面新增角色並關聯使用者),Settings -> Users & Companies -> Users 使用者記錄詳情頁將新增Roles Tab頁

新增並安裝estate_role模組

為了統一管理許可權組,考慮新增一個單獨的應用模組estate_role,模組檔案組織結構如下

custom/estate_role
│  __init__.py
│  __manifest__.py
│
├─security
│      security_estate_property_menu_groups.xml
│      security_estate_property_model_groups.xml
│      security_roles.xml
│
└─views

odoo14\custom\estate_role\security\security_roles.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data noupdate="1">
        <record id="group_role_base_user" model="res.users.role">
            <field name="name">基礎使用者</field>
            <field name="implied_ids" eval="[
                    (4, ref('base.group_user')),
                ]"/>
        </record>

        <record id="group_role_multi_company" model="res.users.role">
            <field name="name">多公司</field>
            <field name="implied_ids" eval="[
                    (4, ref('base.group_multi_company')),
                ]"/>
        </record>

        <record id="group_role_devops" model="res.users.role">
            <field name="name">運維</field>
            <field name="implied_ids" eval="[
                    (4, ref('estate_role.group_estate_property_root_menu')),
                    (4, ref('estate_role.group_estate_property_advertisements_menu')),
                    (4, ref('estate_role.group_estate_property_advertisements_properties_menu')),
                    (4, ref('estate_role.group_estate_property_read')),
                    (4, ref('estate_role.group_estate_property_write')),
                    (4, ref('estate_role.group_estate_property_create'))
                ]"/>
        </record>
    </data>
</odoo>

odoo14\custom\estate_role\__init__.py

檔案內容為空

odoo14\custom\estate_role\__manifest__.py

{
    "name": "Estate Roles",
    "license": "LGPL-3",
    "depends": ["base_user_role"],
    "data": [
        "security/security_estate_property_menu_groups.xml",
        "security/security_estate_property_model_groups.xml",
        "security/security_roles.xml"
    ],
    "installable": True,
}

說明:odoo14\custom\estate\__manifest__.py data列表中已去除上述兩個groups檔案

重啟服務並安裝estate_role模組

檢視效果

使用者詳情頁面,檢視使用者許可權,發現新增 User Roles

編輯使用者,勾選圖中的角色,儲存,發現和角色關聯的許可權組都會被自動勾選了。

注意:

  • 取消勾選已授予的角色,並儲存,不會自動取消勾選角色關聯的許可權組,即取消授予角色操作,不會取消透過授予角色授予給使用者的許可權組
  • 已授予角色給使用者的情況下,取消勾選某個許可權組並儲存,如果該許可權組和授予給使用者的角色關聯,則無法取消勾選的許可權組,因為角色關聯了該許可權組
  • 許可權頁面勾選並儲存的角色,不會在使用者詳情頁的Roles Tab頁中顯示
  • 除了透過在使用者詳情頁-許可權(Access Rights)Tab頁面,選取角色為使用者批次授權外,還可以在使用者詳情頁的Roles Tab頁中為使用者新增角色來實現批次授權。

參考連線

https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/security.html

相關文章