权限系统3个层次结构的LINQ查询
这对我来说有点难以用书面的方式解释,我很欣赏你们花时间阅读这个长长的问题。我打开不使用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不支持递归,但本机sql不支持(公用表表达式)。
我的策略是将所有权限放入列表中,然后编写普通的程序递归代码来回答您的查询(我没有完全理解)。在这种情况下,我推荐TDD。希望这有助于让你走上正轨。
我的看法:只是因为LINQ启用这样的巨大语句并不意味着你应该使用它们。可读性规模非常低。 – 2011-02-07 19:20:49