如何在[Authorize(Roles =“”)]中使用变量

时间:2015-07-29 15:20:15

标签: c# asp.net-mvc

我有一个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网站。有什么方法可以让角色成为变量吗?

4 个答案:

答案 0 :(得分:13)

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

最简单的方法是创建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")]

答案 1 :(得分:4)

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

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

然后用法:

[AuthorizeRoles(RoleConstant1,RoleConstant2)]

答案 2 :(得分:1)

为了使您的代码编译成功,您应该执行您发布的错误消息中所述的内容。

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

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

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

<强>更新

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

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

答案 3 :(得分:0)

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

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;
     }
   }