創建安全組並分配用戶
Odoo中的訪問權限通過安全組成進行配置:給組指定權限,然后為組分配用戶。每個功能區都有中樞應用所提供的基礎安全組。
在插件繼承已有應用時,它們應對相應的組添加權限,參見本章稍后的向模型添加訪問權限一節。
在插件模塊添中添加一個已有中樞應用所未涵蓋的新功能區時,應添加相應的安全組。通常,我們至少應該有用戶和管理員這兩個角色。
以第四章 創建Odoo插件模塊中所介紹的圖書館應用為例,它與Odoo的核心應用並沒有很好的融合,下面我們來對其添加安全組。
准備工作
本節假定你已經准備好了Odoo實例,並且有第四章 創建Odoo插件模塊中所講解的my_module模塊。
如何實現…
執行如下步驟來向模塊添加新的訪問安全組:
- 確保__manifest__.py插件模塊聲明中有定義有category鍵:
1'category': 'Library', - 在聲明文件的data鍵中新增security/groups.xml文件:
1234'data': ['security/groups.xml','views/library_book.xml',], - 在security/library_security.xml中為數據記錄新增XML文件,先使用一個空的結構:
1234<?xml version="1.0" encoding="utf-8"?><odoo><!-- Data records go here --></odoo> - 在XML的data元素中添加兩個新組的record標簽:
12345678910111213141516<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>
如果我們升級該插件模塊,會加載這兩條記錄。要在用戶界面中看到這些組,需要啟用開發者模式。然后就可以通過Settings > Users > Groups菜單項進行查看了。
ℹ️在Odoo v12中,新增模型的默認權限與之前的模型稍有不同。在v12中,如果新增了一個模型,admin用戶對該模型並沒有訪問權限。這表示為該模型所增加的菜單和視圖對admin用戶均不可見。要進行顯示,需要對該模型添加權限組,在向模型添加訪問權限一節中會進行講解。此外,我們可以通過超級用戶來訪問新增的模型,更多相關知識請參見第四章 創建Odoo插件模塊的以超級用戶訪問 Odoo一節。
運行原理…
插件模塊以功能區或主應用進行組織,如財務和金融、銷售或人力資源。它們在聲明文件中以category鍵進行定義。
如果category名稱不存在,會進行自動創建。為方便起見,會為新的分類名創建一個小寫的base.module_category_<category_name_in_manifest>的XML ID,並將空格替換為下划線。 這可以用於通過應用分類來關聯安全組。
本例中,我們使用了Library分類名,它生成了一個base.module_category_library的XML標識符。
按照慣例,包含權限相關元素的數據文件應放在security子目錄內。
還需要在聲明文件中注冊權限文件。模塊聲明中data鍵所聲明文件的順序非常重要,因為無法在其它視圖或ACL文件中引用還未定義的組。最好將權限數據文件放在ACL文件和其它用戶界面數據文件列表的最上面。
本例中,我們使用<record>標簽創建了組,它會在res.groups模型中創建一條記錄。res.groups模型中最重要的字段如下:
- name:這是組的顯示名稱。
- category_id:這是對應用分類的引用,用於在用戶表單中組織分組。
- implied_ids:它們是所要繼承權限的其它組。
- users:這是屬於該組的用戶。在新的插件模塊中,我們通常希望admin用戶屬於應用的管理員組。
第一個安全組使用了implied_ids來作為base.group_user組。它是Employee用戶組,是所有后台用戶所會共享的基本安全組。
第二個安全組在users字段上設置值來將其分配給管理員用戶,其XML ID為base.user_admin。
屬於一個安全組的用戶會自動屬於其所繼承的組。如果為任意用戶分配Librarians組,該用戶會自動的包含在User組中,因為Librarian組s在implied_ids字段中有User組。
同時,安全組所授予的安全權限是累加的。用戶具有他所屬於的任意組(直接授權或通過繼承授權)的權限。
有些安全組在用戶表單中顯示為選擇框而非單個復選框。這種情況發生在所涉及的組在同一應用分類中並且通過implied_ids線性相關聯。例如,Group A繼承自Group B,Group B繼承自Group C。如果組沒有通過implied_ids與任何其它組相關聯,我們看到的會是選擇框,而不是復選框。
注意在前面字段中定義的關聯還有反向關聯,還在關聯的模型中進行編輯,如安全組和用戶。
設置category_id和implied_ids等引用字段的值通過使用關聯記錄的XML ID和一些特殊的語法完成。這種語法在第七章 模塊數據中進行了詳細講解。
擴展知識…
另外值得注意的是特殊的名為Extra Rights的group_no_one安全組。在早期的Odoo版本中,它用於一些默認隱藏的功能,僅在激活了Technical Features 標記時才進行顯示。從9.0,開始發生了一些改變,只要開啟了開發者模式就會顯示這些功能。
通過安全組授予的訪問權限僅可以進行疊加。無法拒絕某個組所授予的權限。這表示手動創建的用於自定義權限的組應繼承最鄰近少於所需權限的組(若有),然后添加剩余所有需要的權限。
組中還可以有以下的額外字段:
- 菜單(menu_access字段):指定組所能訪問的菜單項
- 視圖(view_access字段):指定組所能訪問的UI界面視圖
- 訪問權限(model_access字段):指定組所能訪問的模型,在為模型添加訪問權限一節中會進行詳述
- 訪問規則(rule_groups字段):指定一些應用於組的記錄級訪問規則,在限制模型中字段的訪問一節中會進行詳述
- 提示(comment記錄):這是組的描述或注釋文本
為模型添加訪問權限
為插件模塊新增模型非常的普通。例如在第四章 創建Odoo插件模塊中,我們新增了一個Library Books模型。在開發過程中很容易漏掉對新模型安全權限的創建,這時會很驗證看到所創建的菜單和視圖,因為從Odoo 12起,admin用戶默認對新模型沒有訪問權限。要看到新模型的視圖和菜單,需要添加權限的訪問控制列表(ACL)。
但是沒有ACL的模型在加載時會觸發警告日志消息,告知用戶所漏掉的ACL定義。
1
|
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插件模塊的以超級用戶訪問 Odoo一節。超級用戶的功能僅有管理員(administrator)用戶可用。因此,非管理員用戶如需要使用新模型,需要為他們定義訪問權限列表,這樣Odoo就知道他們能以何種方式訪問以及每個用戶組所能執行的操作有哪些。
准備工作
我們將使用第四章 創建Odoo插件模塊中所創建的模塊,並為其添加所漏掉的ACL。
如何實現…
my_library中應該已經包含了創建library.book模型的models/library_book.py這一Python文件。現在我們會執行如下步驟添加一個描述該模型的權限訪問控制的數據文件:
- 編輯__manifest__.py文件來聲明一個新的數據文件:
12345data: [# ...Security Groups'security/ir.model.access.csv',# ...Other data files] - 在模塊中新增一個包含如下內容的security/ir.model.access.csv文件:
123id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlinkacl_book,library.book_default,model_library_book,base_group_user,1,0,0,0acl_book_librarian,library.book_librarian,model_library_book,group_library_librarian,1,1,1,1
我應當行升級模塊來把這些ACL記錄添加到我們的Odoo數據庫中。更重要的是,如果我們使用demo用戶登錄到演示數據庫中,應該可以訪問Library菜單項且不會出現任何權限錯誤。
運行原理…
權限控制訪問列表存儲在核心的ir.model.access模型中。我們只需要添加描述針對每個用戶組訪問權限的記錄。
任何類型的數據文件都可以,但常用實踐是使用CSV文件。該文件可放在插件模塊目錄中的任何位置,但慣例是將所有安全權限相關的文件放在security子目錄中。
本節中的第一步向聲明文件新增了一個數據文件。第二步添加了一個描述權限訪問控制規則 的文件。CSV文件必須按照所要加載記錄的模型來進行命名,因此所使用名稱不止是一種慣例而是強制如此:參見第七章 模塊數據獲取更多信息。
如果模塊還創建新的安全組,它的數據文件應在聲明文件的ACL數據文件之前進行聲明,因為在ACL中可能會使用到它們。在處理ACL文件時它們必須是已經創建了的。
CSV文件中的字段如下:
- id:這是針對這一規則的XML ID內部標識符。該模塊中的任何唯一名稱都可以,但按慣例使用access_<model>_<group>。
- name:這是訪問規則的標題。常用實踐是使用access.<model>.<group>這一名稱。
- model_id:id:這是該模型的XML ID。Odoo使用model_<name>格式對這些模型自動分配這種類型的ID,使用帶下划線而非點號的模型名稱。如果模弄是在另一個模塊中創建的,則需要完整的包含模塊名稱的有效完整XML ID。
- group_id:id:這是針對用戶組的XML ID。如果留空,它應用於所有用戶。base模塊中提供了一些基本用戶級,比如針對所有用戶的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文件對Employees > Employee標准安全組添加了只讀權限並向Administration > Settings 組添加了全部的寫權限。
Employee用戶組base.group_user尤為重要,因為Odoo標准應用所添加的用戶組都會繼承它。這表示如果我們需要讓所有后台用戶都能訪問新模型的問,不管它們所配使用的具體應用是什么,都應將權限在Employee組中進行添加。
結果產生的ACL可通過訪問Settings > Technical > Security >Access Controls List 來在圖形界面中進行查看,如下圖所示:
TODO
有些人覺得使用用戶界面定義ACL然后用導出功能生成CSV文件會更為容易。
擴展知識…
將這個權限授予創建安全組並分配用戶一節中所定義的User 和Librarian組會顯而易見。如果你按照該節進行操作的話,跟着本節操作會是很好的練習,將組標識符調整為圖書對應的組。
要重點注意不應直接對由插件模塊提供的訪問列表進行自定義,因為它們會在下一次模塊升級時進行重載,破壞在用戶界面中所做的任何自定義內容。
可采用兩種方法來自定義 ACL。一種是創建繼承模塊中所提供組的新安全組並在其上添加新的權限,但這樣我們只能添加權限,不能刪除權限。更靈活的方法是對具體的ACL行取消Active標記的勾選來進行禁用。默認active字段不可見,因此我們需要編輯樹狀視圖來添加<field name=”active” />列。我們還可以添加新的ACL行來添加或替換權限。在模塊升級時,禁用的ACL不會重新激活,添加的ACL行也不會受到影響。
另外值得注意的是ACL僅應用於普通模型,無需對抽象模型或臨時模型進行定義。如若定義,它會被忽略,在服務日志中會打出警告信息。
限制模型中字段的訪問
在某些情況下,我們可能會需要更精准控制的訪問控制,可能會需要限制對模型具體字段的訪問。
可以使用groups屬性來讓字段僅能由指定的安全組所訪問。下面會展示如何添加僅能供圖書模型訪問的字段。
如何實現…
添加僅針對特定安全組有訪問權限的字段,可執行如下步驟:
- 編輯模型文件來添加字段:
12is_public =fields.Boolean(groups='my_library.group_library_librarian')private_notes =fields.Text(groups='my_library.group_library_librarian') - 在XML文件中編輯視圖來添加該字段:
12<field name="is_public" /><field name="private_notes" />
這樣就好了。現在對插件模塊進行升級來應用模型中的修改。如果使用沒有系統配置權限的用戶登錄的話,比如用 demo 用戶登錄帶有演示數據的數據庫,圖書表單中就不會顯示該字段。
運行原理…
帶有groups屬性的字段進行了特殊處理,它檢查用戶是否屬於屬性中所指定的任意安全組。如果用戶不屬於指定的某一組,Odoo會在用戶界面中刪除該字段並限制對該字段的ORM操作。
注意這並不僅僅是表面工作。該字段不僅在用戶界面中會隱藏,同時在用戶的其它ORM操作中也無法使用它,比如讀和寫。對於XML-RPC或JSON-RPC調用同樣如此。
在業務邏輯或用戶界面on-change事件(@api.onchange方法)中使用這些字段時需要小心,在用戶沒有該字段訪問權限時會拋出錯誤。一種避免的方式是使用提權,比如sudo()模型方法或計算字段的compute_sudo字段屬性。
groups的值是包含安全組的有效XML ID的逗號分隔列表的一個字符串。查找 一個指定組的XML ID的最簡單的方式是激活開發者模式並通過Settings > Users > Groups導航到組的表單上,然后通過調試菜單訪問View Metadata選項,如下圖所示:
TODO
擴展知識…
有些情況下,我們需要根據具體條件來讓字段可用或不可用,像字段中的值,比如stage_id或state。這通常使用states或attrs屬性來在視圖級別進行處理來根據特定條件動態顯示或隱藏字段。參見第十章 后端視圖獲取更多詳情。
注意這些技巧僅作用於用戶界面級別,並不提供實際的訪問安全。要實現訪問安全,需要在業務邏輯層添加檢查。要么添加使用@constrains裝飾的模型方法,實現具體的驗證,要么對驗證邏輯繼承create, write或unlink方法。在第六章 基本服務端部署中可以獲取更多的相關知識。
使用記錄規則限制記錄的訪問
對一個應用的常見需求是對指定模型上的每個用戶限制所能使用的記錄。
這通過使用記錄規則來實現。記錄規則是一個定義在模型上的域過濾器表達式,然后添加到所受影響的用戶每個數據查詢上。
作為示例,我們將在圖書模型上添加記錄規則來讓Employee組中的用戶僅能訪問公共圖書。
本節假定你已經准備好了第四章 創建Odoo插件模塊中所講解的my_library模塊,並啟動了實例。
如何實現…
記錄規則使用XML數據文件進行添加。執行如下步驟來進行實現:
- 確保在聲明文件的 data 鍵中添加了security/library_security.xml文件:
1234'data': ['security/library_security.xml',# ...], - 應當有一個security/library_security.xml 數據文件,在<odoo>版塊中創建安全組:
12345678910111213141516171819<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>
升級插件模塊會在Odoo實例中加載記錄規則。如果你使用的是演示數據,可以使用默認的 demo 用戶來將圖書用戶權限授予 demo 用戶進行測試。如果使用的不是演示數據,可以新建一個帶有圖書用戶權限的用戶。
運行原理…
記錄規則僅僅是在 ir.rule 核心模型中所加載的數據記錄。而添加規則的文件可以放在模塊的任意位置,按照慣例會將其放在security子目錄中。在單個XML文件中同時放置安全組和記錄規則很常見。
與安全組不同,在標准模塊中記錄規則是通過noupdate=”1″ 屬性在來odoo代碼區中進行加載的。借助於它,這些記錄不會在模塊升級時重新加載,也就是說對它們做的手動自定義在后續升級中是安全並且會得以保留的。
為保持與官方模塊的一致,我們也應將記錄規則放在<odoo noupdate=”1″>內。
記錄規則在用戶界面中也可以通過Settings > Technical > Security > Record Rules菜單項進行查看,如下圖所示:
TODO
以下是本例中所使用的最重要的記錄規則字段:
- 名稱(name):針對規則的描述性標題。
- 對象(model_id):對規則所應用模型的引用。
- 組(groups):規則所應用的安全組。如未指定安全組,規則應視作全局並使用不同的方式進行應用(繼續閱讀本節來學習有關組的更多知識)。
- 域(domain):域表達式用於過濾記錄。該記錄將僅用於對這些過濾的記錄進行應用。
我們所創建的第一條記錄規則針對Library User 安全組。它使用[(‘is_public’, ‘=’, True)] 來僅選擇公開的圖書。因此Library User安全組中的用戶僅能看到對外開放的圖書。
服務器端在記錄規則中使用的域表達式使用ORM對象。因此,左手邊的字段(元組第一個元素)可使用點號標記。[(‘country_id.code’, ‘=’, ‘IN’)]域表達式會僅顯示國家為印度的記錄。
因為記錄規則多基於當前用戶,你可以使用域中右手邊的用戶記錄集(元組第三個元素)。因此,如果你想要為當前公司的用戶顯示記錄,可以使用 [(‘conpany_id’, ‘=’, user.company_id.id)]域。同時,如果想要顯示由當前用戶創建的記錄,可以使用[(‘user_id’, ‘=’, user.id)]域。
我們希望Librarian安全組能夠看到所有圖書,不論是公開的還是對內的。因其繼承了Library User組,除非進行相關的操作,否則它將僅能看到公開的圖書。
非全局記錄規則使用邏輯運算符OR來進行連接,每條規則增加權限且永不刪除該權限。要讓Librarian能訪問所有圖書,可以將其添加到記錄規則中來為所有圖書添加權限,如下:[(‘is_public’, ‘in’, [True, False])]。
這里我們選擇了不同的方式,沒有使用無條件訪問所有圖書記錄的特殊規則 [(1, ‘=’, 1)]。雖然看起來可能多余,但要記住Library用戶規則可以通過另一種方式來不讓Settings用戶來訪問一些圖書。域很特別,因為域元組的第一個元素必須為字段名,這個用例是並非如此的兩個用例之一。特殊域[(1, ‘=’, 0)]永不為真,但在記錄規則的用例中並沒有什么作用,因為使用這種類型的規則會限制對所有記錄的訪問。在訪問控制列表中也可以做類似的事。
ℹ️在啟用超級用戶時會忽略記錄規則。測試記錄規則時,記得使用其它用戶來進行。
擴展知識…
在記錄規則未分配給任何安全組時,它被標記為全局並由不同的規則來進行處理。
全局記錄規則比組級別的記錄規則影響要更深廣,它設置一些無覆蓋的訪問限制。技術層面,它們通過AND運算符來進行連接。在標准模塊中,它們用於實現多公司安全訪問,這樣每個用戶僅能看到自己公司的數據。
總的來說,常規非全局記錄規則通OR運算符連接在一起,它們在一起添加,僅在其中的規則授予權限時才能訪問對應的記錄。全局記錄規則通過常規記錄規則使用AND運算符來添加訪問限制。全局記錄規則所添加的限制無法由常規記錄規則覆蓋。
使用安全組啟用功能
安全組可以限制一些功能,這樣僅有屬於這些組的用戶才能訪問。安全組也能繼承其它組,因此也繼承它們的權限。
這兩個功能合在一起,用於實現Odoo中的可用性功能:功能切換。安全組也可以用於對Odoo實例中的一些或所有用戶啟用或禁用功能。
本節展示如何對配置設置添加選項並展示啟用額外功能的兩種方法,使用安全組讓它們可見或通過安裝額外的模塊來添加它們。
對於第一種情況,我們將會讓圖書發行日期成為一個可選的額外功能,對於第二種情況,作為示例我們將提供一種選項來安裝Notes模塊。
准備工作
本節使用第四章 創建Odoo插件模塊中所講解的my_library模塊。我們需要使用到安全組,因此還需要按照本章中向模型添加訪問權限一節進行操作。
本節中,一些標識符需要引用插件模塊的技術名稱。我們將假定其為my_library。如果你使用了不同的名稱,請將my_library替換為你的插件模塊中所使用的實際技術名稱。
如何實現…
按照如下給定步驟來添加配置項:
- 要添加所需的依賴和新的XML數據文件,像下面這樣編輯__manifest__.py文件並確保它依賴於base_setup:
1234567891011{'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',],} - 要添加用於啟用功能的新安全組,編輯security/library_book.xml文件並向其添加如下記錄:
12345<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> - 編輯 models/library_book.py文件中的字段定義,來讓圖書發行日期僅在啟用了該選項時可見:
123456class LibraryBook(models.Model):# ...date_release = fields.Date('Release Date',groups='my_library.group_release_dates',) - 編輯models/__init__.py文件來添加針對配置設置模型的新Python文件:
12from . import library_bookfrom . import res_config_settings - 通過向其添加新選項來繼承核心配置向導,添加models/res_config_settings.py文件及如下代碼:
123456789from odoo import models, fieldsclass 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") - 要讓選項在用戶界面中可以使用,添加views/res_config_settings.xml,它繼承表單視圖:
12345678910111213141516171819202122232425262728293031323334353637383940<?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>
在升級了這些插件模塊之后,在Settings > General > Settings 中兩個新的配置選項中應該就可以使用了。參見如下截圖:
TODO
運行原理…
核心base模塊中有res.config.settings模型,它提供了選項激活選項背后的業務邏輯。base_setup插件模塊使用 res.config.settings模型來提供一些基本配置選項來添加到新數據庫中。它還在用戶界面中打開了Settings > General Settings菜單。
base_setup模塊將res.config.settings適配到中央管理儀表盤上,因此我們需要繼承它來添加我們自己的配置設置。
如果我們決定為圖書應用創建具體的設置表單,還可以使用一個不同的_name來繼承res.config.settings模型,然后為這些設置提供菜單項和表單視圖。我們在第九章 高級服務端開發技巧的添加自定義設置選項一節中已進行過相關學習。
我們使用了兩種不同的方法來激活該功能:一種是通過啟用安全組並讓功能對用戶可見,另一種是通過安裝一個帶有該功能的插件模塊。處理這兩種用例的邏輯由res.config.settings 模型提供。
第一步在依賴中添加了base_setup插件模塊,因為它提供對我們想要使用的res.config.settings模型的繼承。它還添加了我們所需的額外的XML數據文件來向General Settings表單添加新的選項。
第二步中,我們創建了一個新的安全組,Library: release date feature。功能的啟用僅對該組可見,這樣直到組啟用時它都會隱藏。
在我們的示例中,我們希望僅在相應的配置項啟用時圖書發行日期才可用。要進行實現,我們對該字段使用groups屬性,這樣它僅對這一安全組可用。我們在模型層面進行了操作,這樣它會自動應用於使用該字段的UI視圖。
最后,我們繼承了res.config.settings模型來添加新選項。每個選項都是一個布爾字段,根據所要實現的功能名稱必須以group_或module_開頭。
group_選項字段應有一個implied_group屬性並且應為一個包含安全組的XML ID逗號分隔列表來在啟用時進行激活。XML ID必須是一種完整的形式,帶有模塊名、點號和標識符名稱,如module_name.identifier。
我們還可以添加group屬性來指定啟用該功能所針對的安全組。如果未定義組,它會對所有基於Employee組的組啟用。因此相關組不應用於門戶(portal)安全組,因為它們沒有像其它常規安全組那樣繼承Employee基安全組,
激活背后的機制相當簡單:對implied_group它在group屬性中添加安全組,因此讓相關的功能對對應的用戶可見。
module_選項字段不需要任何的額外屬性。字段名的剩余部分標識在啟用該選項時安裝的模塊。在本例中,module_note會安裝note模塊。
ℹ️取消復選框的勾選會卸載該模塊並且沒有警告,這會導致數據丟失(會導致模模型或字段以及模塊數據的刪除)。為避免不小心取消勾選,secure_uninstall社區模塊(來自https://github.com/OCA/server-tools))會在卸載插件模塊時彈出要求用戶輸入密碼。
本節的最后一步在Business documents組前添加了General Settings表單視圖,其id=”business_documents”。我們使用該id來進行視圖繼承。它使用模塊名作為id創建了自己的div,這是一種良好實踐,因為這樣繼承my_library的其它模塊可以輕易地向這個div添加配置項。
擴展知識…
配置設置也可以帶有名為default_前綴的字段。其中有值的話,ORM會將其設置為全局默認值。設置字段應有一個default_model屬於,用於標識受影響的模型,default_前綴后的字段名標識有默認值集合的模型字段。
此外,沒琛有這三種前綴的字段可用於其它設置,但你需要使用get_default_為前綴的方法實現邏輯來獲取它們的值,使用set_為前綴的方法來編輯它們的值。
如果想要更深入地了解配置設置,最好的文檔是Odoo的源代碼./odoo/addons/base/models/res_config.py,其中有大量的注釋進行了詳細的講解。
以超級用戶訪問記錄集
在前面小節中,我們學習安全技術,如訪問規則、安全組和記錄規則。使用這些技術,可以規避未授權的訪問。但有時會有復雜的業務用例,其中會需要訪問或修改用戶沒有訪問權限的記錄。例如,公共用戶可能無法訪問線索記錄,但通過提交網站的表單,用戶可以在后台中生成線索記錄。
使用sudo(),可以用超級用戶訪問記錄集。在第九章 高級服務端開發技巧的更改執行動作的用戶一節中我們已學習過sudo()。這里我們將學習到即使有給定的ACL規則或對字段添加了安全組,仍然可以通過sudo()進行訪問。
如何實現…
我們將使用與前面小節相同的my_library模塊。其中已添加了ALC規則,授予了普通用戶只讀權限。我們還將通過安全組新增字段,這樣僅圖書管理員能訪問它。然后,我們將通過普通用戶來修改字段值。按照如下步驟來進行實現:
- 在library.book模型中新增字段:
123report_missing = fields.Text(string="Book is missing",groups='my_library.group_library_librarian') - 在表單視圖中添加該字段:
1<field name="report_missing"/> - 在library.book模型中添加report_missing_book()方法:
1234567def report_missing_book(self):self.ensure_one()message = "Book is missing (Reported by: %s)" %self.env.user.nameself.sudo().write({'report_missing': message}) - 在表單視圖中添加按鈕來在用戶界面中觸發這個方法:
123<button name="report_missing_book"string="Report Missing Book"type="object"/>
重啟服務並更新模塊來應用這些修改。
運行原理…
在第1和第2步中,我們分別在模型和表單視圖中添加了名為report_missing的新字段。注意我們的Python代碼中對該字段添加了my_library.group_library_librarian組,寧樣僅有Librarian組中的用戶才能訪問該字段。
接下來的步驟中,我們添加了report_missing_book() 方法,在方法體中我們更新了report_missing字段的值。注意我們在調用寫方法之前使用了sudo()。
最后,我們在表單視圖中添加了一個按鈕,用於在用戶界面中觸發該方法。
要測試這一實現,需要通過非圖書管理用戶進行登錄。如果你使用演示數據加載了數據庫的話,可以通過demo用戶來登錄,然后點擊圖書表單視圖中的Report Missing Book 按鈕。點擊該按鈕時會調用report_missing_book() 方法,這會在report_missing字段寫入消息,雖然該用戶並沒有相應的權限。可以通過管理員用戶來查看該字段值,因為對demo用戶該字段是隱藏的。
在點擊Report Missing Book按鈕時,我們會在report_missing_book()方法通過 self 參數得到一個當前圖書的記錄集。在圖書記錄集中寫入值之前,我們使用了self.sudo()。這會以不同的環境返回同一記錄集。這條記錄具體通過超級用戶獲取的環境,它會跳過所有訪問規則和記錄規則。因此,非圖書管理用戶就可以對圖書記錄進行寫入。在模型的日志字段write_uid中,其值也是超級用戶。
擴展知識…
在使用sudo()時需要加倍小心,因為它跳過了所有的訪問權限。在多公司環境中,使用不當可能會產生問題。如果你想以另一個用戶訪問記錄的話,可以將該用戶的ID傳遞給sudo,如self.sudo(uid).。這會返回帶有該用戶環境的記錄集。通過這種方法,它不會跳過多訪問規則和權限規則,但你可以執行授予該用戶的所有動作。
根據組來隱藏元素和菜單
在前面小節中,我們學習了如何在Python字段定義中通過group參數來對一些用戶隱藏字段。還有一種在用戶界面中隱藏字段的方式:通過在視圖定義中在XML標簽上添加安全組。也可以對菜單使用安全組來對指定用戶隱藏菜單。
准備工作
本節中,我們將復用前一節中的my_library插件模塊。在前一節中,我們在<header>標簽中添加了一個按鈕。通過對其添加groups屬性我們可以對一些用戶隱藏整個頭部。
為book.category模型添加該模型、視圖和菜單。我們將對用戶隱藏分類菜單。參見第五章 應用模型來學習如何添加模型視圖和菜單。
如何實現…
按照如下步驟來根據安全組隱藏元素:
- 在<header>中添加groups屬性來對其它用戶隱藏它:
123...<header groups="my_library.group_library_user">... - 在<menuitem>圖書分類上添加groups屬性來僅對圖書用戶顯示它:
12345<menuitem name="Book Categories"id="library_book_category_menu"parent="library_base_menu"action="library_book_category_action"groups="my_library.group_library_librarian"/>
重啟服務並更新模塊來應用修改。
運行原理…
第一步中,我們在<header>中添加了groups=”my_library.group_library_user”。這表示整個header部分僅對圖書用戶和圖書管理員可見。不屬於group_library_user的普通后台用戶則無法看到header部分。
第2步中,我們對菜單項添加了groups=”my_library.group_library_librarian”。這樣菜單僅對圖書管理員可見。
幾乎可以在任何地方使用groups屬性,包括<field>, <notebook>, <group>, <menuitems>和視圖結構中的任意標簽。如果用戶不屬於該組的話則會對其隱藏這些元素。可以在網頁和QWeb報表中使用相同的組屬性,這將在第十三章 自動化、工作流和打印件和第十五章 CMS網站開發中進行講解。
正如在本章以超級用戶訪問記錄集一節中所看到的,我們可以在Python字段定義中使用groups參數來對一些用戶隱藏字段。注意字段上的安全組和視圖中的Python安全組有很大的區別。Python中的安全組提供了真正的安全,非授權用戶無法通過ORM或RPC調用來訪問字段。但是視圖中的組僅為了提升易用性。XML文件中通過組隱藏的字段仍可以通過RPC或ORM進行訪問。