自定义CodeAccessSecurityAttribute采取许多角色

时间:2011-12-02 15:20:33

标签: c# .net code-access-security declarative-authorization security-roles

我正在为我们的应用程序开发一些基于角色的安全性,我本质上想要定制verison MVC AuthorizeAttribute - 但仅限于业务逻辑层,我们不链接到MVC。

我看过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,但不确定它将如何启动安全检查。

2 个答案:

答案 0 :(得分:5)

您可以创建一个使用现有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;
    }
}

不幸的是,您无法在安全属性中使用数组,因此角色列表必须表示为字符串。 e.g:

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

您可以通过设计时连接将它与常量一起使用。 e.g:

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

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

答案 1 :(得分:0)

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

基本上,您需要验证allowedRoles.Any(r => Thread.CurrentPrincipal.IsInRole(r))