为什么ClaimsPrincipalPermissionAttribute是密封的,还有其他选择吗



我正在我的.net 4.5应用程序中实现基于声明的安全性。有很多困难需要克服,但它基本上是有效的。

我唯一不喜欢的是我不能创建自己的属性。ClaimsPrincipalPermissionAttribute已密封。为什么?

我总是在整个应用程序中标记,例如:

[ClaimsPrincipalPermission(SecurityAction.Demand, Resource = "Foo", Operation = "Bar")]

由于我希望我的资源和操作字符串不会拼写错误,并且易于重构,所以我创建了类,这样我就可以做到这一点:

[ClaimsPrincipalPermission(SecurityAction.Demand, Resource = Resources.Foo, Operation = Operations.Foo.Bar)]

(注意,由于不同的资源可能有不同的操作,操作本身按资源进行子类化。)

这一切都很好用,但每次打字或复制/粘贴都很麻烦。我宁愿做这样的事情:

[DemandPermission(Resources.Foo, Operations.Foo.Bar)]

我可以创建这个属性,但我需要从ClaimsPrincipalPermissionAttribute继承,因为它是密封的,所以我不能继承。:(

有其他方法吗?也许我不需要继承,但我可以以某种方式注册我自己的属性类型,使其在所有相同的地方工作吗?

ClaimsPrincipalPermissionAttribute源自CodeAccessSecurityAttribute。除了实现CreatePermission()之外,它几乎什么都不做,根据您传入的Resource和Operation的值返回一个新的ClaimsPrincipalPermission

您可以实现一个从CodeAccessSecurityAttribute派生的新类(它不是密封的),它可以满足您的需要。

使用JustDecompile,您可以看到ClaimsPrincipalPermissionAttribute中的代码很简单。你可以这样制作你自己的属性:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
public sealed class DemandPermissionAttribute : CodeAccessSecurityAttribute
{
    public Operations Operation { get; set; }
    public Resources Resource { get; set; }
    public DemandPermissionAttribute(SecurityAction action = SecurityAction.Demand)
        : base(action)
    {
    }
    public override IPermission CreatePermission()
    {
        return new ClaimsPrincipalPermission(this.Resource.ToString(), this.Operation.ToString());
    }
}

需要注意的一件重要事情是,您必须在一个独立的程序集中定义您的自定义属性,而不是引用它的程序集,否则框架将抛出此处描述的TypeLoadException

http://msdn.microsoft.com/en-us/library/vstudio/yaah0wb2.aspx

此外,请注意构造函数参数的默认值的使用。您需要有一个构造函数,该构造函数接受属性的SecurityAction参数,以便由框架实例化。在这种情况下,DemandPermission可能是个坏名字,因为您可以将SecurityAction重写为SecurityAction.Demand之外的其他名称。

ClaimsPrincipalPermissionAttribute已密封。为什么?

Eric Lippert谈到了封闭式框架类型的共性,由于我们谈论的是代码安全性,因此这一点非常重要:

每次实现一个方法,该方法采用未密封类型的实例时,都必须编写该方法,以便在面对该类型的潜在敌对实例时保持健壮。你不能依赖任何你知道对你的实现是正确的不变量,因为一些恶意的网页可能会将你的实现子类化,覆盖虚拟方法来做一些扰乱你逻辑的事情,并将其传入。每次我密封一个类时,我都可以编写使用该类的方法,并确信我知道该类的作用。

这一点更为重要,在这种情况下,ClaimsPrincipalPermissionAttribute通过IClaimsPrincipal接口进行检查。因此,通过使ClaimsPrincipalPermissionAttribute密封,它们允许IClaimsPrincipal的任何实现者都不必担心恶意实现。考虑到这一切都与安全相关,这是一笔可观的节省。

我的第一反应是,这不是一大堆要写的东西——你需要多久写一次?如果它对控制器中的操作是通用的,请将其放置在控制器上——如果适用于许多控制器,请使用该属性创建ControllerBase。

如果你的情况比这更特殊,我想你必须实现你自己的各种属性。

最新更新