在今年的情人節(2018.02.14)那天,我寫了一篇博客說即將要開一個坑,也就是大家在看的這個系列的教程。今天這個系列教程即將迎來它的最後一篇內容了,我們將要來學習 Odoo 中權限相關的內容。
用戶組
在多用戶系統中,並不是所有數據都是可以開放給全部用戶的,所以在多用戶系統中,權限管理是非常重要的一環。通常我們會根據業務和組織架構對用戶進行分組管理,也就是我們常說的用戶組或角色組,然後再根據用戶組對用戶所能接觸到的數據內容進行控制。
在 Odoo 的權限管理體系中,同樣也有用戶組這一概念的存在,和其他框架(如 Django)可以說大同小異。回到我們的 Todo 應用裏來,從一開始我們就是用的超級管理員賬戶 admin
登錄和操作的,這在任何生產環境和測試環境裏都是不允許出現的,但是在前面的教程裏,我們都沒有提到過賬戶和權限相關的內容,是爲了讓教程能一路走下來,所以我們今天就來糾正這個錯誤。
在我們的 Todo 應用中,假設有「用戶」和「管理員」兩個用戶組,普通用戶可以創建、修改和刪除自己創建的待辦事項,而管理員除了擁有普通用戶的操作權限外,還可以創建、修改和刪除分類數據。
現在我們就來看看應該如何定義這兩個用戶組,和定義其他數據一樣,我們同樣需要在 xml 文件中定義用戶組數據,找到模塊下的 security
目錄,然後創建一個 todo_security.xml
文件,用於定義我們的用戶組數據:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record id="module_category_todo" model="ir.module.category">
<field name="name">待辦事項</field>
</record>
<record id="group_todo_user" model="res.groups">
<field name="name">用戶</field>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
<field name="category_id" ref="todo.module_category_todo"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="group_todo_manager" model="res.groups">
<field name="name">管理員</field>
<field name="implied_ids"
eval="[(4, ref('base.group_user')), (4, ref('todo.group_todo_user'))]"/>
<field name="category_id" ref="todo.module_category_todo"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
</data>
</odoo>
這裏總共有 3 條記錄,分別是 Todo 模塊分類(ir.module.category
)和「用戶」及「管理員」兩個用戶組(res.groups
),重點來看看用戶組裏各個字段所代表的含義:
-
category_id
:該用戶組所屬的模塊分類 -
implied_ids
:在當前用戶組下的用戶,同時加入該字段所指定的用戶組中 -
users
:該字段所指定的用戶默認被加入到當前用戶組中
在上面的記錄中,還有兩個引用(ref
),分別是 base.group_user
基礎用戶組和 base.user_root
管理員賬戶。
別忘了把 'security/todo_security.xml'
加入到 __manifest__.py
的 data
列表中,將它放在 # 'security/ir.model.access.csv'
這一行的上面,然後升級更新模塊之後打開設置菜單下的「用戶」菜單,打開管理員賬戶 Administrator
的表單視圖。
這時我們可以看到在「Application Accesses」下出現了我們剛剛創建的「待辦事項」模塊分類,進入編輯模式後,可以看到有「用戶」和「管理員」兩個選項
可以發現超級管理員賬戶已經默認被分配到了待辦事項分類下的「管理員」組中了,這也和我們前面說的 users
字段所表現的行爲是一致的,再返回列表,打開 Demo User
這個賬戶看看,是不是並沒有加入我們創建的用戶組中的任何一個呢 :)
用戶組權限
用戶組創建好了之後,事情遠遠還沒有結束,因爲我沒並沒有爲這兩個用戶組分配相關數據的操作權限。那如果我們現在創建一個新的用戶,並且加入到任意的用戶組中,然後登錄訪問系統,會發生什麼呢?實踐出真知,我們來創建一個 test
用戶並且分配到「用戶」組中,然後登錄看看會發生什麼
注:修改新創建的賬戶密碼,打開 Action 下拉菜單,點擊 Change Password 即可修改
打開隱身窗口或者在另一個瀏覽器上登錄,你會看到頁面上什麼都沒有,爲什麼會這樣?
不要感到迷惑,這確實是因爲我們沒有給用戶組分配任何數據的操作權限導致的,用戶沒有對數據的讀寫權限,自然就無法查看到相關的內容了。在 Odoo 中給用戶組分配權限,是以模型爲單位的,也就是說只有某個用戶組被分配了對應模型的權限之後,該用戶組內的用戶才能操作對應模型下的數據。用戶組權限的定義是以 .csv
格式文件存儲的,在創建模塊時默認已經生成了一個權限記錄文件 security/ir.model.access.csv
,打開它我們可以看到裏面有一條記錄,這是在創建模塊時自動生成的,可以看到裏面有 8 個字段,分別代表的含義如下
-
id
:這條權限記錄的 id,可以類比爲xml_id
-
name
:權限記錄的名稱 -
model_id:id
:要配置權限的模型的外部 ID (以model_
開頭) -
group_id:id
:應用此條權限配置的用戶組的 id,若爲空則默認對所有用戶組生效 -
perm_read
:讀取記錄的權限,1 爲擁有該權限,0 爲不分配該權限 -
perm_write
:編輯更新記錄的權限,取值同上 -
perm_create
:創建新記錄的權限,取值同上 -
perm_unlink
:刪除記錄的權限,取值同上
如果不理解也沒關係,我們先來給「用戶」組添加對模型 todo.task
的操作權限,通過實例會更容易理解:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_todo_task_user,todo.task.user,model_todo_task,group_todo_user,1,1,1,1
我們在這裏爲「用戶」組(group_todo_user
)添加了對 todo.task
待辦事項模型的讀寫創建和刪除四個操作的權限,然後打開 __manifest__.py
並將 # 'security/ir.model.access.csv'
這行的註釋取消掉,然後升級更新模塊,然後刷新剛剛登錄的 test
賬戶的界面,是不是可以看到有數據了呢
終於不是空空如也的頁面了,可是有沒有覺得哪裏不對呢?是的,這個賬戶是新的賬戶,但是卻看到了超級管理員創建的數據,拋開這個問題不管先,這個我們後面會再來解決。現在我們要做的是創建一條新的記錄,看看能不能成功創建一條新的記錄
Oops! 在選擇分類的時候突然彈出了個錯誤,這是怎麼回事呢,來仔細看看錯誤提示的內容
對不起,你沒有權限訪問該文檔。如果你認爲這是一個錯誤,請聯繫系統管理員。
(文檔模型:todo.category)
看起來問題並不在我們的待辦事項(todo.task
)模型上,而是在分類模型上,我們剛剛分配用戶組權限時只分配了待辦事項模型的權限,所以當用戶視圖讀取分類模型的數據時,就會提示沒有權限訪問。解決這個問題同樣很簡單,只需要加上分類模型的權限即可
access_todo_category_user,todo.category.user,model_todo_category,group_todo_user,1,0,0,0
將上面的權限定義加到 ir.model.access.csv
文件的行末,然後升級更新模塊後再次創建,這次終於成功創建起來了。
對權限分配這部分內容的認識有沒有比剛開始更開始要清晰一些了呢?那我們這裏就留一個小作業吧:
爲用戶組「管理員」添加權限,允許該用戶組下的用戶對分類模型進行管理,包括創建、刪除、更新和讀取
如果不知道寫得是否正確,可以參考源碼中的我的寫法。
記錄集權限
用戶組權限是粒度較粗的權限控制方式,它只能針對於某一個模型的全部記錄應用相關權限配置,但是某些時候,我們會需要粒度更細的權限控制方式。一個現成的例子就是上一節中,我們用新建的測試賬戶登錄後,可以看到超級管理員所創建的待辦事項的記錄,這是不合理的,一個普通的用戶,應該只能看到和操作他所創建的記錄。
值得慶幸的是,Odoo 爲我們提供了基於記錄集的權限控制方式,我們可以很輕鬆地根據業務需求編寫相應的規則,將權限控制的粒度精細到具體的記錄上。爲了體現記錄集權限的用法,我們將假設在我們的 Todo 應用中,普通用戶只能讀取和操作由自己創建的待辦事項,而管理員則可以查看和刪除(但不能修改)所有用戶創建的待辦事項。
通常和權限相關的內容,我們都會在模塊的 security
目錄下進行定義,記錄集規則的定義自然也不例外。我們創建一個 ir_rule.xml
的文件,然後添加記錄集規則的定義
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="rule_todo_task_user" model="ir.rule">
<field name="name">待辦事項規則 - 用戶</field>
<field name="model_id" ref="model_todo_task"/>
<field name="domain_force">[('create_uid', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('todo.group_todo_user'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
<record id="rule_todo_task_manager" model="ir.rule">
<field name="name">待辦事項規則 - 管理員</field>
<field name="model_id" ref="model_todo_task"/>
<field name="domain_force">[('create_uid', '!=', user.id)]</field>
<field name="groups" eval="[(4, ref('todo.group_todo_manager'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="True"/>
<field name="perm_unlink" eval="True"/>
</record>
</data>
</odoo>
之後要做的事當然就是把 'security/ir_rule.xml'
添加到 __manifest__.py
的 data
中啦,再來就是升級更新模塊,現在刷新瀏覽器,應該看不到其他用戶創建的待辦事項記錄了,完美達成目的~現在讓我們回到管理員賬戶所在的瀏覽器,然後創建一個新的賬戶,並添加到「管理員」組內,接着再新開一個隱身窗口登錄這個新創建的管理員賬戶,我們可以看到和預期的結果一樣,管理員可以看到全部用戶創建的待辦事項記錄,隨便點擊一條記錄並編輯,修改任意內容後保存,這時候你會發現彈出了一個錯誤警告
這個錯誤提示我們當前用戶沒有權限修改這一條記錄,就如我們前面的假設一樣,管理員不能修改其他用戶創建的記錄,剩下的創建和刪除,大家可以隨意測試。
看完了效果之後,又到了解釋說明的時間了,我們先來看到定義的規則裏最後四個屬性字段,是不是很熟悉呢?沒錯,這就是我們在定義用戶組權限時所看到的表示讀寫創建和刪除這四個操作的屬性,在記錄集權限的定義裏,他們的含義是一樣的,只不過屬性值從 0 和 1 變成了 True 和 False,然後我們再來看看另外幾個字段:
-
model_id
:要應用該規則的模型的外部 ID -
domain_force
:過濾條件,符合該條件的記錄都將按照所定義權限進行檢查,其中變量user
表示當前用戶的實例對象,可以直接使用 -
groups
:應用該規則的用戶組,如果不指定則默認對全部用戶應用該規則
菜單隱藏
目前爲止,一切看起來都很不錯,不過還有點美中不足。我們再次打開測試賬戶所在的瀏覽器窗口,我們前面留了一個小作業,分類只允許管理員進行管理,那麼我們自然不希望普通用戶看到多餘的菜單內容了,所以某些時候用戶雖然對某些數據具有可讀的權限,但是未必會想要開放對應的菜單入口給這些用戶。而我們要根據用戶組來對菜單的可見性進行處理,其實也很簡單,只需要在對應的菜單項上添加一個 groups
屬性即可,裏面的值可以是逗號分隔的多個用戶組的外部 ID,以「分類」菜單爲例
<!-- views/menus.xml -->
<menuitem action="action_todo_category" id="submenu_todo_category" name="分類"
parent="menu_todo_submenu" sequence="8" groups="todo.group_todo_manager"/>
就這麼簡單,更新模塊之後刷新瀏覽器看看,「分類」菜單是不是已經被隱藏起來了呢,而管理員賬戶依然可以看到該菜單。除了菜單外,在視圖的字段上也可以通過添加屬性 groups
達到針對不同的用戶組隱藏相關字段的目的。
寫在最後
雖說這是「Odoo 基礎教程系列」的最後一篇內容了,但是這不意味着之後不會再寫 Odoo 相關的內容了,感謝大家一直以來的支持,雖然很小衆,但是也有不少小夥伴給予了一些正面的鼓勵,雖然更新速度很慢很慢,但是這個系列終於還是完成啦!自我感覺還是有很多寫得不好的地方,希望以後可以寫得更好~
如果大家有什麼問題想要得到解答,可以加入羣裏,和其他小夥伴一起交流或者提問,添加下面這個微信,備註 Odoo 加羣,通過後將會拉入羣裏的 :)