2011-02-01 77 views
1

我有一个安全模式,某些实体通过SecureEntity引用进行安全保护。 SecureEntity具有一组RolePermissions,每个RolePermissions都有一个允许标志和一个优先级。这个想法是将用户的角色与SecureEntity上的RolePermissions进行匹配。例如,用户可能被其最低优先级权限所允许,但被较高权限所拒绝,因此它是我们感兴趣的最高权限。在此示例中,我查询的根实体称为ProcessCategory。将这个Sql查询翻译成NHibernate Linq或Criteria?

Schema

(SecureRoleId是匹配用户的角色; SecureRoleName只是一个字符串描述。)

假设一个用户角色(1,2)和SecureEntity有RolePermissions:

SecureRoleId = 1, Priority = 0, Allow = true 
SecureRoleId = 2, Priority = 1, Allow = false 

在这种情况下,实体将不会被选中。但是,如果用户只有角色1,则会选择该实体。当然,SecureEntity可能包含一些用户没有且无关紧要的其他角色。

下面的sql代码的工作原理是:'如果用户拥有的最高优先级角色权限Allow = true,则选择该实体。所以它基本上将RolePermission过滤到用户自己的角色(IN子句)上,按优先级进行排序,如果这是允许,则将其作为最高级别。

这里是SQL:

select pc.* from ProcessCategory pc 
join SecureEntity se 
    join RolePermission rp on se.SecureEntityId = rp.SecureEntityId 
on pc.SecureEntityId = se.SecureEntityId 
where rp.RolePermissionId = (select top 1 RolePermissionId 
       from RolePermission 
       where Allow = 1 
       and SecureEntityId = se.SecureEntityId 
       and SecureRoleId in(0,1) 
       order by Priority desc) 

有可能是另一种方式来写上面的SQL,但它确实是我所需要的。理想情况下,我想用NHibernate Linq或Criteria来实现这一点。我花了几个小时试图让Linq工作,并在RolePermission的内部连接上发生了各种“无效操作”异常。我没有很多ICriteria或MultiCriteria的经验,如果有人能帮助我,我会感兴趣。

注意,对于对象流利映射是直接的:

<some-entity>.References(x => x.SecureEntity) 

SecureEntity.HasMany(x => x.RolePermissions).Not.Inverse(); 

回答

0

好。我无法使用原生 NH Linq工作,尽管这并不意味着这是不可能的。但是我查看了Linq的所有NH单元测试,并且找不到任何相同的东西。

得到它的工作我创建了一个数据库函数调用UserHasPermission,做一切在:

on pc.SecureEntityId = se.SecureEntityId 
where rp.RolePermissionId = (select top 1 RolePermissionId 
      from RolePermission 
      where Allow = 1 
      and SecureEntityId = se.SecureEntityId 
      and SecureRoleId in(0,1) 
      order by Priority desc) 

这适用于任何类型的担保实体。然后按照本页中的说明将该功能映射为NH Linq功能:http://wordpress.primordialcode.com/index.php/2010/10/01/nhibernate-customize-linq-provider-user-defined-sql-functions/

如果您按照这些说明进行操作,则必须在C#中创建一个与您的数据库签名相同的正常LinqToObjects扩展。然后,你可以做你NH Linq查询,如:

return base.Query<T>().Where(c => ((ISecureEntity)c) 
      .SecureEntity.Id 
      .UserHasPermissions(user.SecureRoleIdsCsv) == 1); 

我发现了,我原来的SQL函数返回了一下,这是我映射到NH布尔类型的唯一问题。然而,这产生了一个非常奇怪的SQL,其中有几个“Where”True“'='True''”子句在Sql Server中爆发。所以我将结果更改为一个整数,一切正常。有点反直觉,但...

这样做,让我继续透明地使用Linq我所有的查询,而不会影响现有的代码,因为它会自动预先安全检查每个查询。

请注意,我查看了犀牛安全源代码,它使用了一个复杂的标准,这对我而言非常复杂,以至于我对有限的NH知识的理解。如果我使用CreateCriteria完成它,我可以将它与Linq结合吗?

  • 在上面的链接的说明不说清楚,当你创建了自己的方言,其登记您的SQL函数,你必须确保你引用它在你的NH配置文件(或者代码),否则你会得到某种'未知类型'异常。