c# - 承担多种角色的自定义 CodeAccessSecurityAttribute

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

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

我查看了 PrincipalPermissionAttribute 但似乎没有办法自定义它,因为它是密封的。我只想创建一个自定义版本,在其中可以检查角色列表中任何的成员资格,而无需使用多个属性,并且还可以定义在何处查找角色成员资格。

.Net 中是否有我缺少的类似内容?或者有人知道如何在不重新实现 ASP.Net 的 AuthorizeAttribute/RoleProvider/etc 的情况下做到这一点吗?

编辑

我目前正在运行一个命令式版本,但我宁愿有一个声明性属性版本,因为在方法/类上方更容易看到它。

现在我的业务层的抽象基类中有以下内容:

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 只是可注入(inject)角色提供程序属性的外观,我可以将其设置为使用 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,则可以将其替换为自定义主体,该主体使用自定义角色提供程序来检索目标身份的角色。

关于c# - 承担多种角色的自定义 CodeAccessSecurityAttribute,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8358503/

相关文章:

c# - 是否存在 finally block 不被执行的情况?

c# - 数据库优先+EF+POCO; T4代码生成?

java - 什么等同于 Java 中的 .NET SortedDictionary?

.net - 在 F# 中定义静态类

java - 如何防止 Java 系统属性发生更改(在 Java EE 中)?

c# - 如何避免在每次回发时调用 ModelState.IsValid?

.net 数据包嗅探 : attempt to create socket causes access error

c# - 如何在不违反继承安全规则的情况下在 .NET 4+ 中实现 ISerializable?

C# 使用 WebTestRequest 运行并发请求