這對我來說有點難以用書面的方式解釋,我很欣賞你們花時間閱讀這個長長的問題。我打開不使用LINQ查詢來解決這個問題,只是做一些類型的循環或遞歸,如果更好的工作。權限系統3個層次結構的LINQ查詢
我正在使用基於NETSqlAzMan的權限/授權系統。
這些是主要的概念:
- 權限是可以授權給定的兩個「安全對象」的權利。
- 「安全」是可以作出兩個授權(Think用戶或用戶組在這裏)的對象,以及它們可以作爲的對象(認爲文件或文檔)。例如:User1和File1都是「安全」,User1可以被授權編輯File1。
- 「安全」可以有父母和子女的「安全」。
- 「權限」可以擁有父級和/或子級權限。
這是如何工作的更具體的例子。
安全對象:
- Administrators
- Tom
- Mike
- Editors
- John
- Lisa
- Documents
- Document1
- Document2
權限:
- Edit_Document
- Edit_Title
- Edit_Body
- Change_BGColor
上述數據存儲在2個表中,安全性和權限有2箇中間表,GroupMembership(安全層次結構)和PermissionRelationship(權限層次結構)。
還有一個稱爲Authorization的表,它包含由一個Securable組成的「AuthorizedID」,一個Securable作爲「SecurableID」,一個Permission作爲「PermissionID」以及一個Enum,它們可以是Inherit 0),允許(1)或拒絕(2)。
我有LINQ2SQL實體設置爲所有表以及一個函數返回給定的Securable的祖先和一個返回給定的權限的祖先的所有。
我很努力地確定一個查詢,可以正確檢查每個權限的所有3個層次結構,以確定對於給定的AuthorizedID和SecurableID設置授權的有效權限和最近的授權ID級別。
例如: 如果管理員正在爲「Edit_Document」權限授予「允許」的「文檔」,然後爲「管理員」和「文檔」 SecurableiD給定AuthorizedID查詢應該返回:
- AuthorizedID:管理員SecurableID:文檔允許許可:Edit_Document
- AuthorizedID:管理員SecurableID:文檔允許許可:Edit_Title
- AuthorizedID:管理員SecurableID:文檔允許許可:Edit_Body
- AuthorizedID:管理員SecurableID:文檔允許許可:Change_BGColor
如果另外的授權被增加了對「文檔1」,「邁克」與拒絕「Change_BGColor」(拒絕覆蓋任何允許在鏈進一步向下),則查詢的 「邁克」 的AuthorizedID和 「文檔1」 的SecurableID的結果將返回:
- AuthorizedID:管理員SecurableID:文件允許權限:Edit_Document
- AuthorizedID:管理員SecurableID:文件允許權限:Edit_Title
- AuthorizedID:管理員SecurableID:文件允許權限:Edit_Body
- AuthorizedID:邁克SecurableID:文檔1拒絕權限:Change_BGColor
這是我迄今爲止,處理AuthorizedID的層次和SecurableID罰款,但沒有按」請適當考慮權限的層次結構。我不確定如何將權限層次結構考慮在內,以便如果某個權限的祖先被設置爲拒絕,那麼子權限也顯示拒絕,並且結果包括設置了拒絕的AuthorizedID和SecurableID。
public List<LocalPermission> GetSecurablesLocalPermissions(Guid authorizedID, Guid securableID)
{
var localAuthorization = (from eff in
(from p in dc.Permissions
let a = (from sa in dc.AllSecurablesAuthorizations(authorizedID)
where sa.PermissionID == p.PermissionID
group sa by sa.PermissionID into g
select g.OrderBy(x => x.Lvl).OrderByDescending(x => x.AuthorizationBits).First()).FirstOrDefault()
select new
{
PermissionID = p.PermissionID,
PermissionName = p.PermissionName,
AuthorizationBits = a.AuthorizationBits ?? 0,
SecurableID = a.SecurableID ?? Guid.Empty,
SecurableName = a.SecurableName,
AuthorizedName = a.AuthorizedName,
AuthorizedID = a.AuthorizedID ?? Guid.Empty
})
join l in
(from p in dc.Permissions
join la in dc.Authorizations
on p.PermissionID equals la.PermissionID into laJoin
from localJoin in laJoin.Where(x => (x.SecurableID == securableID /*|| localJoin.SecurableID == Guid.Empty*/) && (x.AuthorizedID == authorizedID /*|| localJoin.AuthorizedID == Guid.Empty*/)).DefaultIfEmpty()
select new
{
PermissionID = p.PermissionID,
PermissionName = p.PermissionName,
AuthorizationBits = localJoin == null ? 0 : localJoin.AuthorizationBits,
SecurableID = localJoin == null ? Guid.Empty : localJoin.SecurableID,
SecurableName = localJoin == null ? null : localJoin.SecurableName,
AuthorizedName = localJoin == null ? null : localJoin.AuthorizedName,
AuthorizedID = localJoin == null ? Guid.Empty : localJoin.AuthorizedID
}) on eff.PermissionID equals l.PermissionID
select new LocalPermission
{
PermissionID = l.PermissionID,
PermissionName = l.PermissionName,
AuthorizationBits = l.AuthorizationBits,
SecurableID = securableID,
SecurableName = (from s in dc.Securables
where s.SecurableID == securableID
select s).SingleOrDefault().SecurableName,
AuthorizedID = authorizedID,
AuthorizedName = (from s in dc.Securables
where s.SecurableID == authorizedID
select s).SingleOrDefault().SecurableName,
EffectiveAuthorizationBits = eff.AuthorizationBits == 0 ? l.AuthorizationBits : eff.AuthorizationBits
}).ToList<LocalPermission>();
return localAuthorization;
}
我的看法:只是因爲LINQ啓用這樣的巨大語句並不意味着你應該使用它們。可讀性規模非常低。 – 2011-02-07 19:20:49