为什么ClaimsPrincipalPermissionAttribute是密封的,还有替代方案吗?

时间:2012-08-22 20:00:03

标签: c# wif custom-attributes .net-4.5 claims-based-identity

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

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

3 个答案:

答案 0 :(得分:7)

ClaimsPrincipalPermissionAttribute来自CodeAccessSecurityAttribute。除了实现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参数,以便由框架实例化。在这种情况下,DemandPermission可能是个坏名称,因为您可以将SecurityAction覆盖为SecurityAction.Demand以外的其他内容。

答案 1 :(得分:3)

  

ClaimsPrincipalPermissionAttribute已被密封。为什么呢?

Eric Lippert谈到了封装在Framework类型中的共性,因为我们讨论代码安全性,所以这一点非常重要:

  

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

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

答案 2 :(得分:1)

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

如果您的案例比这更特殊,我想您将被迫实施各种属性。