C# 在ASP.NET MVC中使用SQL中基于[Flags]的枚举到int权限管理进行访问控制
这个问题的灵感来自于ASP.NET MVC。在这里,我试图将公认的答案转化为切实可行的解决方案 答案提到使用C# 在ASP.NET MVC中使用SQL中基于[Flags]的枚举到int权限管理进行访问控制,c#,sql,sql-server-2008,enums,enum-flags,C#,Sql,Sql Server 2008,Enums,Enum Flags,这个问题的灵感来自于ASP.NET MVC。在这里,我试图将公认的答案转化为切实可行的解决方案 答案提到使用FileSystemSecurity作为管理权限的灵感。在这里,我还使用带有Flags属性的enum来定义我所有对象的ACL。此外,我的对象的每个成员都将存储在SQL中的一列中。假设一个简化的Linq2SQL、EF或nHibernate ORM映射 编辑:添加了此方法的以下优点/基本原理 此安全模型的灵感来自管理文件级权限的.NET方法 我喜欢这种方法的一个主要原因是,我可以通过将所有AC
FileSystemSecurity
作为管理权限的灵感。在这里,我还使用带有Flags属性的enum来定义我所有对象的ACL。此外,我的对象的每个成员都将存储在SQL中的一列中。假设一个简化的Linq2SQL、EF或nHibernate ORM映射
编辑:添加了此方法的以下优点/基本原理
此安全模型的灵感来自管理文件级权限的.NET方法
我喜欢这种方法的一个主要原因是,我可以通过将所有ACL合并在一起,轻松创建所有权限的摘要。我还喜欢添加拒绝ACL以删除继承的权限
List<myObject> PermissionsList = GetACLForObject(ItemID, UserID);
foreach (var acl in PermissionsList)
{
// The following enum has the [FlagsAttribute] applied so the .ToString() is pretty
PermissionWithFlagsEnum sampleForSO = (PermissionWithFlagsEnum )acl.Permission;
Console.Writeline ("Setting " + sampleForSO.ToString() + " permission for group: " + acl.ACLName);
ResultingPermission = resultPermission | acl.Permission ;
}
public int ResultingPermission {get;set;}
我有一个将用户ID连接到特定于对象的ACE的。这将减少对特定行的并发更新的需要。
问题
- 这是个好主意吗
- 以前有人做过吗(比这更好)?(编辑:)
- 如果这是实现权限的标准方式,那么它叫什么
- 许多简单的查询(删除此身份验证的用户)不是 因为之前需要执行位运算 比较
- 另外
从权限中选择用户< DBAceessRights.DetailRead可能不会返回正确的结果,因为
大于DetailRead,但不大于 打开DetailRead。所以你希望得到的好处可能无法实现AppearInListing&CreateNew
- 管理并发(多个写入程序到ACL)更加困难,因为改变一个“逻辑值”实际上就是改变所有的值
- 许多简单的查询(删除此身份验证的用户)不是 因为之前需要执行位运算 比较
- 另外
从权限中选择用户< DBAceessRights.DetailRead可能不会返回正确的结果,因为
大于DetailRead,但不大于 打开DetailRead。所以你希望得到的好处可能无法实现AppearInListing&CreateNew
- 管理并发(多个写入程序到ACL)更加困难,因为改变一个“逻辑值”实际上就是改变所有的值
- 您假设您需要的权限不超过32个(如果使用
,则为64个)。对我来说,这听起来像是一个任意的限制。在数据库中移动到bigint
可以克服这一问题,但是您的枚举就麻烦了(无法在varbinary
上创建枚举)!你将无法进行数字比较byte[]
- 您假设特权
在逻辑上总是小于0x1
和0x2
,依此类推。在我的经验中,这种情况很少发生。更常见的情况是,权限相互独立(即:“添加用户”权限与“上传图像”权限无关;一组用户(管理员)拥有前者,而其他用户(内容发布者)拥有后者。这意味着您的数字比较没有您最初认为的那么有用0x80
- 您所做的可能会带来性能方面的好处,但您还没有证明存在性能问题!大多数我的权限系统使用每个用户一条数据库记录来授予或拒绝每个权限。获取100条记录不会对我的数据库征税。与usi相比,您最好在请求之间缓存每个用户的权限正在使用位掩码
- 关于更新性能:用户权限多久更改一次?根据我的经验,一旦系统就位,它们往往是相当静态的 我发现,当试图将大量数据打包到一个小空间中时,位掩码最有用。但是,当我最终拥有超过64件东西时,我的第1点常常会反过来咬我 请注意,我在记录用户操作的统计信息(跟踪用户在搜索中找到的项目、查看的实体等)时使用了这种技术。我的原因纯粹是为了确保数据库记录长度固定且较小,因此插入速度较快。我没有做数字比较。(平心而论,我从未测试过
- 我会说不
int
列和几个bit
列之间是否存在任何差异)
编辑
一个基本的选择(我正在使用):用户和权限(我称之为权限)之间的m:N关系
(很抱歉我的用户有米老鼠耳朵!)
UserRight
中有记录表示该用户被授予了权限。没有记录表示没有权限。此查询提供了分配给用户的所有权限
SELECT [dbo].[User].Username, [dbo].[Right].Id, [dbo].[Right].Name
FROM [dbo].[Right]
INNER JOIN [dbo].[UserRight] ON [dbo].[Right].Id = [dbo].[UserRight].RightId
INNER JOIN [dbo].[User] ON [dbo].[User].Id = [dbo].[UserRight].UserId
WHERE [dbo].[User].Id = @pUserId
然后,在代码中声明用户有权:
var grantedRights = RunTheAboveQuery(currentUser.Id);
if (grantedRights.Any(r => r.Id == requiredRight))
// User has the right.
else
// User does not have the right.
显然,您可以扩展它来检查一个用户在一个查询中拥有多个权限
这并没有人为地限制系统支持的特权数量,也没有假设特权之间存在任何关系(所以你不能进行数字比较,一切都是如此)
var grantedRights = RunTheAboveQuery(currentUser.Id);
if (grantedRights.Any(r => r.Id == requiredRight))
// User has the right.
else
// User does not have the right.