授权具有多个角色的属性

时间:2014-06-12 10:14:33

标签: c# asp.net-mvc authorization

我想将Authorization添加到控制器,同时为多个角色添加。

通常情况如下:

[Authorize(Roles = "RoleA,RoleB,RoleC")]
public async Task<ActionResult> Index()
{
}

但是我已将我的角色存储在角落中,因为它们可能会在某些时候改变或扩展。

public const RoleA = "RoleA";
public const RoleB = "RoleB";
public const RoleC = "RoleC";

我不能这样做,因为字符串必须在编译时知道:

[Authorize(Roles = string.join(",",RoleA,RoleB,RoleC)]
public async Task<ActionResult> Index()
{
}

有没有办法规避这个问题?

我可以编写一个只包含“RoleA,RoleB,RoleC”的const - 但我不喜欢魔术字符串,这是一个神奇的字符串。更改角色名称而忘记更改组合字符串将是一场灾难。

我正在使用MVC5。 ASP.NET Identity和Role在编译时是已知的。

5 个答案:

答案 0 :(得分:159)

尝试创建自定义授权属性,例如this

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

假设您的角色对于多个控制器是相同的,请创建一个帮助类:

public static class Role
{
    public const string Administrator = "Administrator";
    public const string Assistant = "Assistant";
}

然后像这样使用它:

public class MyController : Controller
{
    [AuthorizeRoles(Role.Administrator, Role.Assistant)]
    public ActionResult AdminOrAssistant()
    {                       
        return View();
    }
}

答案 1 :(得分:8)

确保您从System.Web.Mvc.AuthorizeAttribute而不是System.Web.Http.AuthorizeAttribute派生自定义属性类。

我遇到了同样的问题。一旦我改变它,一切都有效。

您可能还想将以下内容添加到自定义属性类中:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 

答案 2 :(得分:7)

我发现解决此问题的最佳和最简单的方法就是在Authorize属性中连接角色。

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

使用CustomRole一个具有常量字符串的类:

public static class CustomRoles
{
    public const string Admin = "Admin";
    // and so on..
}

答案 3 :(得分:3)

我所做的就是@Tieson的答案

我在他的回答中略微调整一下。而不是string.Join为什么不将它转换为列表?

以下是我的回答:

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    private new List<string> Roles;
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = roles.toList()
    }
}

然后检查角色是否有效覆盖OnAuthorization

public override void OnAuthorization(HttpActionContext actionContext)
{
            if (Roles == null)
                HandleUnauthorizedRequest(actionContext);
            else
            {
                ClaimsIdentity claimsIdentity = HttpContext.Current.User.Identity as ClaimsIdentity;
                string _role = claimsIdentity.FindFirst(ClaimTypes.Role).Value;
                bool isAuthorize = Roles.Any(role => role == _role);

                if(!isAuthorize)
                    HandleUnauthorizedRequest(actionContext);
            }
        }

如果你拥有它,它现在正在验证角色是否有权访问资源

答案 4 :(得分:0)

除非你有大量的角色,否则我觉得自定义授权属性对此问题来说是过度的。

由于字符串必须在编译时知道,为什么不创建一个包含已定义角色的公共字符串的静态Role类,然后添加逗号分隔的字符串以及您要授权的某些角色:

public static class Roles
{
    public const string ADMIN = "Admin";
    public const string VIEWER = "Viewer";

    public const string ADMIN_OR_VIEWER = ADMIN + "," + VIEWER;
}

然后您可以在Controller类或Controller方法(或两者)上使用Authorize Attribute:

[Authorize(Roles = Roles.ADMIN]
public class ExampleController : Controller
{
    [Authorize(Roles = Roles.ADMIN_OR_VIEWER)
    public ActionResult Create()
    {
        ..code here...
    }
}