MVC 5 自定义属性枚举列表作为参数

MVC 5 custom attribute enumeration list as parameter

我有一个关于自定义授权属性 (MVC 5) 和代表用户角色的枚举列表的问题。首先我有这个自定义授权属性

[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class CustomAuthorizationAttribute : AuthorizeAttribute
{
    public Enums.Roles[] AllowedRoles { get; set; }
}

角色枚举

public enum Roles
{
    uknown = 0,
    Admin= 100,
    Guest = 200,
}

我用来限制用户访问我想使用的某些控制器和方法的静态列表

public static class AuthorizationHelpers
{
   public static readonly Enums.Roles[] AccessToIndivindual = {
       Enums.Roles.Admin,
       Enums.Roles.Guest,
   };
}

在我的控制器中,当我使用以下内容并指定枚举角色列表时,授权按预期工作

    [CustomAuthorization(AllowedRoles = new[] { Enums.Roles.Admin, Enums.Roles.Guest})]
public class HomeController
{
   ....
}

我需要的是将静态只读枚举列表与我希望允许访问 controller/method 的所有角色一起使用,例如 AccessToIndivindual。为了重用它们。我试过这样的东西

[CustomAuthorization(AllowedRoles = AuthorizationHelpers.AccessToIndivindual )]
public class HomeController
{
   ....
}

但每次我这样使用它时,我都会得到

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

有没有一种方法可以使用角色列表作为枚举作为属性参数来实现这一点?

这是设计使然,我只看到 Xunit 中有一种解决方法。他们在使用 inlinedata 属性创建参数化测试用例(理论)时遇到了类似的问题。他们引入了可能使用反射来处理它的 classdata 和 memberdata 属性。请参阅以下 post 了解其他人如何使用它:http://hamidmosalla.com/2017/02/25/xunit-theory-working-with-inlinedata-memberdata-classdata/

属性是元数据,必须在编译时知道,因此必须是 conststatic readonly 字段不是 const,包含项目的数组不能声明为 const

如果要将字段用作 AllowedRoles 的值,则需要使用 Flags enum.

[Flags]
public enum Roles
{
    uknown = 1,
    Admin= 2,
    Guest = 4,
}

然后你可以声明一个const

public const Roles _AccessToIndivindual = Roles.Admin | Roles.Guest;

并在您的 CustomAuthorizationAttribute 中将其用作

[CustomAuthorization(AllowedRoles = _AccessToIndivindual )]
public class HomeController()
{
    ....
}

在花了很多时间试图通过避免枚举标志来找出解决这个问题的方法之后,在阅读了 Stephen Muecke 的回答之后,我得出的结论是我必须重构整个授权实现。因此,如果有人试图实现类似的授权逻辑,请避免使用带有枚举角色的静态列表,并从一开始就使用标志。 here 发布了一个非常有用的答案,其中包含有关枚举标志的解释。

所以这里是我必须做的改变才能完成这项工作。

public static class Enums
{
  [Flags]
  public enum Roles
  {
    uknown = 0,
    Admin= 1 << 1,
    Guest = 1 << 2
  }
}

创建一个 const 枚举,其中包含被授权执行操作的角色

public static class AuthorizationHelpers{
    public const Enums.Roles Can_Save_Product = Enums.Roles.Admin| Enums.Roles.Guest;
}

授权属性

[CustomAuthorization(Allowed_Roles = AuthorizationHelpers.Can_Save_Product )]
public class HomeController
{
     .....
}

最后在我的 CustomAuthorization 属性中

[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class CustomAuthorizationAttribute : AuthorizeAttribute
{
     public Enums.Roles Allowed_Roles { get; set; }
}

每次我想检查当前角色是否被授权时,我可以使用

进行检查
AuthorizationHelpers.Can_Save_Product.HasFlag(role.ToEnum<Enums.Roles>()))

还要提一下,当针对标志枚举使用 ToString() 时,它会创建一个漂亮的逗号分隔的授权角色字符串,可以轻松将其转换为数组。只是不要忘记 trim 结果,因为每个逗号

后都有一个 space
this.Allowed_Roles.ToString().Split(',').Select(u=>u.Trim()).ToArray();