自定义CodeAccessSecurityAttribute,需要很多角色

问题描述:

我正在为我们的应用程序的一些基于角色的安全性,我基本上想要做定制verison MVC的AuthorizeAttribute - 但只在业务逻辑层,我们没有链接到MVC。自定义CodeAccessSecurityAttribute,需要很多角色

我已经看过PrincipalPermissionAttribute,但它似乎没有办法自定义它,因为它是密封的。我只想创建一个自定义版本,我可以在不使用多个属性的情况下检查角色列表中任意的成员资格,还可以定义在哪里查找角色成员资格。

在.NET中是否有这样的东西,我错过了?或者有没有人有一些洞察如何做到这一点,而不重新实现ASP.Net的AuthorizeAttribute/RoleProvider /等?

编辑

我现在有一个当务之急运行的版本,但我宁愿有一个声明属性的版本,因为它更容易看到它的方法/类以上。

现在我有一个抽象基类,以下为我的业务层:

protected void EnsureEditorLevelAccess() 
{ 
    var allowedRoles = new[] 
          { 
           Roles.Administrator, 
           Roles.Editor, 
          }; 

    var roles = GetAccountRoles(GetCurrentUsername()); 

    if (roles.Any(role => allowedRoles.Contains(role))) 
    { 
     return; 
    } 

    throw new SecurityException("You do not have sufficient privileges for this operation."); 
} 

我喜欢能够使用Roles.Administrator等,因为角色名是可怕的(基于Active Directory组...) ,所以我正在考虑将这些细节包装在一个自定义属性的构造函数中,我可以在类/方法的顶部放置它。

GetAccountRoles只是一个可注入的角色提供程序属性的外观,我可以设置它使用AD或使用数据库的测试版本。

我可以子类Attribute,但不知道它将如何启动安全检查。

您可以创建一个使用现有PrincipalPermission的新属性,如果这足以满足您的需求。如果您现有的命令式实现使用PrincipalPermission,则应该是这种情况。但是,如果您的命令式版本执行其他操作,则可能需要考虑实现自定义权限和相应属性。如果你不知道这是否是必要的,也许你可以分享一些细节就你目前的当务之急办法......


问题更新后...

它实际上可以使用“任何“与PrincipalPermission的逻辑,尽管它需要多个实例的联合,这在属性中使用并不特别实用。这使得它更合理,以创建一个自定义属性,它可能看起来像下面这样:

[Serializable] 
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = false)] 
public sealed class AnyRolePermissionAttribute : CodeAccessSecurityAttribute 
{ 
    public AnyRolePermissionAttribute(SecurityAction action) 
     : base(action) 
    { 
    } 

    public string Roles { get; set; } 

    public override IPermission CreatePermission() 
    { 
     IList<string> roles = (this.Roles ?? string.Empty).Split(',', ';') 
           .Select(s => s.Trim()) 
           .Where(s => s.Length > 0) 
           .Distinct() 
           .ToList(); 

     IPermission result; 
     if (roles.Count == 0) 
     { 
      result = new PrincipalPermission(null, null, true); 
     } 
     else 
     { 
      result = new PrincipalPermission(null, roles[0]); 
      for (int i = 1; i < roles.Count; i++) 
      { 
       result = result.Union(new PrincipalPermission(null, roles[i])); 
      } 
     } 

     return result; 
    } 
} 

不幸的是,你不能使用安全属性阵列,所以角色列表已被表示为一个字符串。例如:

[AnyRolePermission(SecurityAction.Demand, Roles = "Foo, Bar")] 

您可以通过设计时连接将它与您的常量一起使用。例如:

[AnyRolePermission(SecurityAction.Demand, Roles = Roles.Administrator + ", " + Roles.Editor)] 

至于您的自定义角色提供程序,使用它的适当位置在线程主体中,而不是权限或属性。例如,如果您当前正在使用GenericPrincipal,则可以使用使用您的自定义角色提供程序的自定义主体来替换它以检索目标标识的角色。

+0

我加入当前的代码,如果你想看看它质疑。 –

+0

为什么你不能使用数组?我没有在任何地方看到这个文档...... – Jeff

+1

@ JeffN825:你不能使用数组,因为处理权限属性的CLR机制不支持它。这只是MSDN文档中未包含的许多权限属性的一个特性。 –

您可以派生自己的CodeAccessSecurityAttribute并围绕Thread.CurrentPrincipal(http://msdn.microsoft.com/en-us/library/system.security.permissions.codeaccesssecurityattribute.aspx)实现您的逻辑。

本质是,你要验证allowedRoles.Any(r => Thread.CurrentPrincipal.IsInRole(r))

+0

是的,这听起来正是我想要做的,但不知道我如何覆盖“验证此权限”的机制,以确认上述“验证我们有这些权限之一” 。 –