如何扩展AuthorizeAttribute并检查用户的角色

时间:2011-02-25 13:26:34

标签: c# asp.net asp.net-mvc asp.net-mvc-2 asp.net-mvc-3

我正在为我的动作方法MyAuthorizeAttribute写我自己的自定义属性,我仍在忙着编写代码,这是我的部分代码:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class  MyAuthorizeAttribute : AuthorizeAttribute
{
   public new Role Roles;

   public override void OnAuthorization(AuthorizationContext filterContext)
   {
      base.OnAuthorization(filterContext);

      if (Roles != 0)  // Did it this way to see what the value of Roles was
         return;

      // Here I am going to get a list of user roles
      // I'm doing my own database calls

      filterContext.Result = new HttpUnauthorizedResult();
   }
}

这是我的角色枚举:

public enum Role
{
   Administrator = 1,
   SuperAdministrator = 2
}

我的行动方法:

[MyAuthorize(Roles = Role.Administrator|Role.SuperAdministrator)]
public ActionResult Create()
{
   return View();
}

我没有使用Roles =“Administrator,SuperAdministrator”的原因是角色是硬编码的。如果角色名称发生变化,我不希望有100个地方可以更改。

根据我的方法,当它到达if(Roles!= 0)然后Roles总值为3时,我如何检查这两个角色是否在特定用户的用户角色列表中?

我在这里做得对吗?如果不是,我将如何实现这一点?它不一定是我做的方式。

2 个答案:

答案 0 :(得分:6)

如果MyAuthorizeAttribute接受了IList(或类似的),那会不会更好 这样它既是类型安全的,但你不必使用位标志。 如果你想保存reult,那么位标志很棒,但这是另一种方式。

编辑(现在有例子):

Attribute:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public Role[] RoleList { get; set; }


    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
        {
            throw new ArgumentNullException("httpContext");
        }
        IPrincipal user = httpContext.User;
        if (!user.Identity.IsAuthenticated)
        {
            return false;
        }
        //Only role access is implemented here
        /*if ((this._usersSplit.Length > 0) && !this._usersSplit.Contains<string>(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
        {
            return false;
        }*/
        if ((RoleList.Length > 0) && !RoleList.Select(p=>p.ToString()).Any<string>(new Func<string, bool>(user.IsInRole)))
        {
            return false;
        }
        return true;
    }

}

控制器:

[MyAuthorize(RoleList = new []{Role.Administrator , Role.SuperAdministrator} )]
    public ActionResult Create()
    {
        return View();
    }

答案 1 :(得分:3)

如果我理解正确,那么您的问题不在于继承AuthorizeAttribute,而在于比较枚举值。您可能想要一个可以用作位标志的枚举类型 - 如果是这样,请查看the section about Enumeration Types in the C# Programming guide,尤其是第二部分,“枚举类型为位标志”。

澄清一下:

您现在可以执行以下操作,而不仅仅是检查Roles!=0

public override void OnAuthorization(AuthorizationContext filterContext)
{
    base.OnAuthorization(filterContext);

    // Here you get an enum indicating the roles this user is in. The method
    // converts the db information to a Role enum before it is returned.
    // If the user is not authenticated, the flag should not be set, i.e. equal 0.
    Role userRole = GetUserRolesFromDatabase();

    // Bitwise comparison of the two role collections.
    if (Roles & userRole > 0)
    {
        // The user is in at least one of the roles in Roles. Return normally.
        return;
    }

    // If we haven't returned yet, the user doesn't have the required privileges.
    new HttpUnauthorizedResult(); 
}

为了使比较更容易,您可以在枚举上使用以下扩展方法:

public static class RolesExtensions
{
    public static bool HasAnyOf(this Roles r1, Roles roles)
    {
        return (r1 & roles) > 0;
    }
}