4

我正在我的 .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 继承,因为它是密封的,所以我不能。:(

还有其他方法可以解决这个问题吗?也许我不需要继承,但我可以以某种方式注册自己的属性类型,以便它在所有相同的地方工作吗?

4

3 回答 3

7

ClaimsPrincipalPermissionAttribute源自CodeAccessSecurityAttribute。它几乎什么都不做,除了根据您传入的 Resource 和 Operation 的值实现CreatePermission()返回一个新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参数,以便由框架实例化属性。在这种情况下, MaybeDemandPermission是一个坏名字,因为您可以将 覆盖SecurityActionSecurityAction.Demand.

于 2013-11-01T16:41:19.740 回答
3

ClaimsPrincipalPermissionAttribute 是密封的。为什么?

Eric Lippert谈到了Framework 类型中sealed 的共性,既然我们在谈论代码安全,这一点非常重要:

每次您实现一个采用未密封类型实例的方法时,您必须编写该方法以使其在面对该类型的潜在敌对实例时具有健壮性。你不能依赖任何你知道对你的实现是正确的不变量,因为一些恶意网页可能会继承你的实现,覆盖虚拟方法来做一些弄乱你的逻辑的东西,然后把它传递进去。每次我密封一个类,我可以编写使用该类的方法,并确信我知道该类的作用。

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

于 2012-08-28T17:42:09.443 回答
1

我的直接反应是,这不是很多要写的——你需要多久写一次?如果它适用于控制器中的操作,请将其放在控制器上 - 如果适用于许多控制器,请创建具有该属性的 ControllerBase。

如果你的情况比这更特殊,我想你被迫实现你自己的那个属性。

于 2012-08-28T17:28:04.007 回答