2011-05-03 84 views
25

我想爲ACL創建模式;然而,我在執行它的幾種方法之間撕裂。ACL的數據庫模式

我很確定我不想處理級聯權限,因爲這會導致後端和站點管理員很大的混淆。

我想我也可以和用戶一起生活,一次只能在一個角色中工作。像這樣的設置將允許隨着網站的增長而添加角色和權限,而不會影響現有的角色/規則。

起初我要規範化數據,並有三張表來表示關係。

ROLES { id, name } 
RESOURCES { id, name } 
PERMISSIONS { id, role_id, resource_id } 

找出被允許的地方,用戶是否會像這樣的查詢:

SELECT id FROM resources WHERE name = ? 
SELECT * FROM permissions WHERE role_id = ? AND resource_id = ? ($user_role_id, $resource->id) 

然後我意識到,我只會有大約20個資源,每個多達5個動作(創建,更新,查看等),也許還有8個角色。這意味着我可以公然無視數據規範化,因爲我永遠不會有超過幾百條可能的記錄。

所以也許這樣的模式會更有意義。

ROLES { id, name } 
PERMISSIONS { id, role_id, resource_name } 

這將讓我查找在單個查詢

SELECT * FROM permissions WHERE role_id = ? AND permission = ? ($user_role_id, 'post.update') 

那麼其中哪些是更正確的記錄?是否有ACL的其他架構佈局?

+4

您也可以使用正確,正確的規範化架構在單個查詢中查找權限。使用'JOIN'。 – 2011-05-08 23:15:48

+2

我對級聯權限的直接體驗是,我(軟件開發人員/維護人員)很難獲得正確的權限,但是對於管理員來說,生活更加美好。部分原因是我包含在權限用戶界面中,可以查看您有權執行的操作,以及*爲什麼*您有權執行此操作。所以他們可以很容易地看到許可來自哪裏。這對他們來說非常直觀。 – btilly 2011-05-11 17:58:04

回答

28

以我的經驗,真正的問題大多發生故障是否不特定用戶訪問限制的任何數額將要發生。

例如,假設您正在設計社區的模式,並允許用戶切換其配置文件的可見性。

一種選擇是堅持公共/私人標誌並堅持廣泛的先發制人的權限檢查:'users.view'(views public users)vs'users.view_all'(查看所有用戶,版主)。 (a)所有人都可以查看,(b)他們親自挑選的好友可以查看,(c)完全保持私密狀態,也許(d)除了他們精心挑選的bozos之外的所有人都可以看到。在這種情況下,您需要存儲單個行的所有者/訪問相關數據,並且您需要大量抽象這些內容,以避免實現密集的,面向圖的傳遞閉包。

不管採用哪種方法,我發現,在角色編輯/分配增加的複雜性是由產生便於/靈活性分配權限,數據的各個部分抵消,而下面以最好的工作:

  1. 用戶可以有多個角色
  2. 角色和權限在同一表中合併標誌來區分兩個(有用的編輯時的角色/燙髮)
  3. 角色可以分配其他角色,並且角色和燙髮可以分配權限(但權限不能驢來自同一個表的內部角色)。

所得到的取向圖然後可以在兩個查詢拉,使用您正在使用哪個語言內置一勞永逸在合理的時間量,並緩存到內存緩存或後續使用類似。

從那裏,拉取用戶的權限是檢查他擁有哪些角色,並使用權限圖處理它們以獲得最終權限。通過驗證用戶是否具有指定的角色/權限來檢查權限。然後根據該權限檢查運行您的查詢/發出錯誤。

如果需要,您可以擴展對個別節點的檢查(例如,check_perms($user, 'users.edit', $node)代表「可編輯此節點」,check_perms($user, 'users.edit')代表「可編輯節點」),您將擁有非常靈活/易用的終端用戶。

正如開場示例應該說明的那樣,請謹慎對待行級權限。性能瓶頸在檢查單個節點的權限時比在拉取有效節點列表時(即只有那些用戶可以查看或編輯的節點的權限)更少。如果你不是非常精通查詢優化的話,我會建議不要在行之內的flags和user_id字段以外的任何東西。

+0

謝謝你對更復雜的關係的良好概述。我會想象這是類似Facebook的權限圖類型將使用。我記得前一段時間跟一個關於角色的人談過,他提到了許多需要多角色的邊緣案例。唯一引起我關注的是,將圖形存儲在內存中所需的對象/數組的大小至少爲1兆字節。它似乎只是查詢你需要的部分,並將圖形留在數據庫中會節省大量的RAM。 – Xeoncross 2011-05-10 18:34:03

+0

對於我遇到的權限圖,結果實際上非常小。但是,我從來不需要管理數百個角色。 :-) – 2011-05-10 18:38:33

+0

實際上,我試圖想到一些例子,其中單個對象也需要權限 - 但我想不出他們應該屬於圖中的時間。如果這是您所說的用戶配置文件許可,我同意配置文件行應包含一個位列。如果是某個角色的私人論壇,我認爲這也應該放在論壇對象中。你是否還有其他一些不適用於角色的情況例子? – Xeoncross 2011-05-10 18:58:04

0

您可以使用SET來分配角色。

CREATE TABLE permission (
    id integer primary key autoincrement 
    ,name varchar 
    ,perm SET('create', 'edit', 'delete', 'view') 
    ,resource_id integer); 
+0

規則在手之前是未知的。雖然在大多數資源上都需要基本的CRUD規則,但可能存在其他自定義規則,因此SET不能在項目開始時定義SET。 – Xeoncross 2011-05-04 20:28:56

+0

您可以使用'ALTER TABLE'擴展設置。 – Johan 2011-05-04 20:47:19

+0

嗯,問題是這些規則對於某些模塊是獨一無二的。也許「修改」是文章的許可,「退款」是支付系統的許可。此外,ALTER TABLE在大型數據集上的速度不是很快,每次需要添加新權限時都很麻煩。 – Xeoncross 2011-05-05 15:25:03

7

這意味着我可以行使公然無視 數據規範化,因爲我 將永遠不會有超過兩 百能記錄更多。

您期望的行數不是選擇哪種標準形式的標準。規範化涉及數據完整性。它通常通過減少冗餘來提高數據完整性。

真正要問的問題不是「我會有多少行?」,而是「對數據庫總是給我正確的答案有多重要?」對於將用於實現ACL的數據庫,我會說「非常重要」。

如果有的話,少量的行表明你不需要關心性能,所以5NF應該是一個簡單的選擇。在添加任何ID號碼之前,您需要先按5NF。

查詢弄清楚,如果用戶正在 允許地方看起來像 這樣:

SELECT id FROM resources WHERE name = ? 
SELECT * FROM permissions 
WHERE role_id = ? AND resource_id = ? ($user_role_id, $resource->id) 

你寫的採用內部的,作爲兩個查詢,而不是加入提示您可能在你的頭上。 (這是一個觀察,而不是批評。)

SELECT p.* 
FROM permissions p 
INNER JOIN resources r ON (r.id = p.resource_id AND 
          r.name = ?) 
+0

5NF中的ACL模式會是什麼樣子? – Xeoncross 2011-05-08 23:44:44

+0

完全同意,最重要的是表格應該保持清晰。如果你想在速度方面進行優化,那麼你應該查看數據庫中的位文件,一些具有固定ACL元素的應用程序使用位域和位操作來執行ACL檢查,但是這比少數有明確關係和未來擴展的表可用。就速度而言,應用程序可以在應用程序級對象中的所有ACL表完成初始加載後緩存ACL對象,並使用應用程序語言而不是SQL執行檢查。 – regilero 2011-05-10 13:24:28