【问题标题】:How can I use a variable in [Authorize(Roles="")]如何在 [Authorize(Roles="")] 中使用变量
【发布时间】:2017-09-23 22:25:01
【问题描述】:

我有一个 MVC 5 C# Intranet Web 应用程序,我们在其中使用了 30 多个 Active Directory 角色,并且由于业务文化,权限经常发生变化。

为了方便我自己,我想我会尝试这样的事情来确定允许谁访问控制器操作或子操作。

/* This function runs a LINQ query and outputs a comma delimited string of 
   approved active directory roles.
*/

    private static string _approvedRoles = 
            Helpers.QueryableExtensions.GetApprovedRoles("FourCourseAudit");

    // GET: FourCourseAudits    
    [Authorize(Roles = _approvedRoles)]
    public ActionResult Index(string searchBy="All", 
          string orderBy="Campus", string orderDir="Asc")
    {

    // and so on... 

不幸的是,我收到了这个编译时错误:An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

这是我尝试使用 _approvedRoles 变量的其他方法(例如 public const stringpublic string)之后的位置。我将GetApprovedRoles 函数放置在模型、存储库(现在所在的位置)和控制器主体中。

我知道这些角色很好,因为如果我使用这个:[Authorize(Roles="DOMAIN\Role1,DOMAIN\Role2")] 它可以工作。这对我来说不是一个可行的选择,因为角色发生了变化,而且这是一个非常大的 MVC 站点。有什么方法可以让 Roles 成为变量吗?

【问题讨论】:

  • 属性(如错误所示)不是动态的,因为它们不能具有更改运行时的值。我不在 ASP 中使用 MVC,但我使用的其他框架允许我检查请求的上下文以获取用户的角色并在方法内进行比较,如果不允许则返回错误...
  • 所以你要覆盖属性

标签: c# asp.net-mvc


【解决方案1】:

需要在编译时知道参数,但您的查询发生在运行时。

最简单的方法是创建一个custom AuthorizeAttribute。在Authorize() 方法中,您可以进行任何您想要的检查,包括查询数据库。如果您希望更灵活地重用属性,也可以将自定义参数传递给构造函数。举个例子:

public class RoleAuthorizeAttribute : AuthorizeAttribute
{
    // or inject it
    private DbContext _db = new DbContext();

    private string _filter;

    public RoleAuthorizeAttribute(string filter)
    {
        _filter = filter;
    }

    /// <summary>
    /// Check authorization
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var currentUser = HttpContext.Current.User;

        // do some checks, query a database, whatever
        string approvedRoles =  Helpers.QueryableExtensions.GetApprovedRoles(_filter);

        if (!currentUser.IsInRole(...))
        {
            filterContext.Result = new RedirectToRouteResult("Error", new RouteValueDictionary());
        }
    }
}

并使用:

[RoleAuthorize("FourCourseAudit")]

【讨论】:

  • 我有时也直接从 Attribute 继承,这就是 AuthorizeAttribute 继承自
  • 这看起来很有希望。我将如何将此覆盖应用于特定字符串,例如“FourCourseAudit”?在我的示例中,我使用该字符串作为 where 过滤器返回了已批准的角色。
  • 我更新了一个如何将参数传递给属性的示例,例如“FourCourseAudit”。就您实际检查的方式而言,这取决于您的 GetApprovedRoles() 返回什么,以及您的业务逻辑应该是什么。
  • 快到了。没有编译时错误,但是当我尝试它时,我收到了 HTTP 500 错误。我是否必须将此类保存在特定的命名空间或文件夹中?
  • 不,它可以去任何地方。错误是什么?您可能需要启用对抛出异常的中断(在“调试”菜单 > 异常 > 并确保检查公共语言运行时异常是否已抛出)。
【解决方案2】:

这对任何想要它的人来说都是一个简单的版本:

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    public AuthorizeRolesAttribute(params string[] roles)
    {
        Roles = String.Join(",", roles);
    }
}

当时的用法是:

[AuthorizeRoles(RoleConstant1,RoleConstant2)]

【讨论】:

    【解决方案3】:

    为了使您的代码编译成功,您应该按照您发布的错误消息中的说明进行操作。

    例如,您可以尝试这样的事情:

    [Authorize(Roles = "Admin,User")]
    

    简单来说,作为参数传递给属性的值在编译时应该是已知的。它们无法在运行时进行评估。

    更新

    正如我在下面的评论中所说:

    唯一的选择是构建自定义属性并获得批准的角色。然后,您可以检查当前的用户角色是否属于已批准的角色,并且您的自定义属性(您的过滤器)将允许或不允许使用调用此操作。

    【讨论】:

    • 谢谢。我已经意识到这一点。我希望有另一种方法可以使用变量。
    • 唯一的选择是构建一个自定义属性并获得批准的角色。然后,您可以检查当前的用户角色是否属于已批准的角色,并且您的自定义属性(您的过滤器)将允许或不允许使用调用此操作。
    【解决方案4】:

    您始终可以定义从 AuthorizeAttribute 和 ovveride AuthorizeCoreHandleUnauthorizedRequest 扩展的新类 并创建一个具有所有常量角色的静态类,声明我在我的应用程序中的操作方式。

    AuthorizeCore 方法中我的自定义类属性中的代码示例

        public string Groups { get; set; } // this will be my new attribute
        var groups = Groups.Split(',').ToList();
    
        var context = new PrincipalContext(ContextType.Domain,"myDomain");
        var userPrincipal = UserPrincipal.FindByIdentity(context,IdentityType.SamAccountName,httpContext.User.Identity.Name);
    
        foreach(var group in groups){ // will iterate the attribute and check if that user log is in that group
         if(userPrincipal.IsMemberOf(context, IdentityType.Name, group)){
                                return true;
         }
       }
    

    【讨论】:

      猜你喜欢
      • 2021-03-24
      • 2019-11-02
      • 2013-09-06
      • 1970-01-01
      • 2020-10-28
      • 2014-10-08
      • 2023-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多