【问题标题】:Can not have [Authorize()] with dynamic code inside不能有 [Authorize()] 里面有动态代码
【发布时间】:2019-04-17 12:06:45
【问题描述】:

我试图让授权接受角色作为枚举或smart enum 这样我就不必调试魔术字符串及其拼写错误

但我一直因为这两个错误而陷入死胡同:

  • 属性构造函数参数“roles”的类型为“Role[]”,它不是有效的属性参数类型

  • 属性参数必须是属性参数类型的常量表达式、typeof表达式或数组创建表达式

这是我的代码:

AuthorizeRoles.cs

public class AuthorizeRoles : AuthorizeAttribute
{
    public AuthorizeRoles(params Role[] roles)
    {
        string allowed = string.Join(", ", roles.ToList().Select(x => x.Name));
        Roles = allowed;
    }
}

Role.cs

public class Role
{
    public readonly string Name;

    public enum MyEnum  // added
    {
        Admin,
        Manager
    }

    public static readonly Role Admin = new Role("Admin");
    public static readonly Role Manager = new Role("Manager");

    public Role(string name)
    {
        Name = name;
    }

    public override string ToString()
    {
        return Name;
    }

在我的控制器内部我做了这个

    [AuthorizeRoles(Role.Admin, Role.Manager)]
    [AuthorizeRoles(Role.MyEnum.Admin)] // added 
    public IActionResult Index()
    {
        return Content("hello world");
    }

我已经看过这些答案,但它不起作用

【问题讨论】:

  • @SᴇM 一开始是,后来我改成了smart-enum
  • 你的 smart-enum 不是一个枚举,所以这不起作用。使用真正的枚举就可以了。
  • 属性不能这样做,你需要编译器说的常量表达式。枚举或字符串可能是您最好的选择。
  • 你仍然可以引用事物,你可以做类似[AuthorizeRole(typeof(Role), nameof(Role.Admin))]的事情,你需要使用反射来获取实际的字段或属性值。
  • @thehennyy 我已经用枚举完成了,仍然发生同样的问题

标签: c# asp.net asp.net-core asp.net-core-mvc


【解决方案1】:

由于 CLR 约束(属性如何存储在元数据中),属性参数只能是原始类型或这些类型的数组(以及Types)。您不能Role(自定义对象)传递给属性。

枚举是有效的,但编译器无法将您的枚举 (Role.MyEnum) 转换为 Role,这是 AuthorizeRoles 的构造函数需要的类型。所以这是一个编译器错误。

你可以猜到,解决方案是创建一个构造函数,它采用Role.MyEnum 的数组,如下所示:

public class AuthorizeRoles : Attribute
{
    public string Roles { get; private set; }

    public AuthorizeRoles(params Role.MyEnum[] roles)
    {
        string allowed = string.Join(", ", roles);
        Roles = allowed;
    }
}

public class Role
{
    public readonly string Name;

    public enum MyEnum
    {
        Admin,
        Manager
    }

    public Role(string name)
    {
        Name = name;
    }

    public override string ToString()
    {
        return Name;
    }
}

// ...

[AuthorizeRoles(Role.MyEnum.Admin)]
public IActionResult Index()
{
    // ...
}

【讨论】:

    【解决方案2】:

    在构造函数 AuthorizeRoles 类中,您使用 Role 类的数组,但在属性 [AuthorizeRoles(Role.MyEnum.Admin)] 中,您使用 MyEnum 类型的参数。如果要使用枚举,则必须创建 AuthorizeRoles 类构造函数,参数为 MyEnum 类型。

    【讨论】:

      【解决方案3】:

      诚然,这很糟糕,但你可以在这里真正做到这一点的最接近的是:

      public static class Roles
      {
          public const string Admin = "Admin";
          public const string Manager = "Manager";
      }
      

      然后:

      [Authorize(Roles = Roles.Admin + "," + Roles.Manager)]
      

      在常量字符串的组合和适当的字符串连接之间,它仍然是一个“常量表达式”。你不能做的基本上是任何需要运行方法的事情,比如string.Join。这就是使用属性时的游戏中断。

      【讨论】:

      • 您可能仍在使用您的“智能枚举”,但它不起作用。它需要更新不是常量的对象。我提供示例静态类是有原因的。这是唯一可行的方法。
      • 因为你不能使用ToString()only 它的工作方式与我在答案中发布的完全一样。你一直在尝试其他东西,然后告诉它不起作用。当然不是。如果您不想在属性本身上硬编码字符串值,这是您唯一的选择。期间。
      【解决方案4】:

      使用常量作为策略名称并使用授权策略

      // 启动.cs

      services.AddAuthorization(options =>
              {
                  options.AddPolicy(PolicyConstants.Admin, policy =>
                  {
                      // Allowed to access the resource if role admin or manager
                      policy.RequireClaim(JwtClaimTypes.Role, new[] { PolicyConstants.Admin, PolicyConstants.Manager });
      
                     // Or use LINQ here
                      policy.RequireAssertion(c =>
                      {
      
                          // c.User.Claims
                      });
      }
      

      在控制器中使用策略名称

      [Authorize(PolicyConstants.Admin)]
      public class TestController
      {
          // here also you can use specific policy and for controller, you can use other policy. It will match Action Level policy first and then match controller policy.
          public IActionResult Index()
          {
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-22
        • 1970-01-01
        • 2020-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-14
        相关资源
        最近更新 更多