授权具有多个角色的属性


97

我想一次为多个角色的控制器添加授权。

通常情况如下:

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

但是我将我的角色存储在const中,因为它们有时可能会更改或扩展。

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身份和角色。


您是否使用公共常量字符串RoleA =“ RoleA”; 还是如您所写的那样?
Mukesh Modhvadiya 2014年

Answers:


188

尝试像这样创建自定义授权属性。

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

12
现在,这是值得Mac Gyver使用的想法;)
Christian Sauer

2
很不错的解决方案:)
AUP

1
我也非常喜欢这种解决方案,特别是因为我可以让我的角色成为枚举而不是字符串。在项目层次结构中放置自定义授权属性的良好名称空间和位置是什么?
Simon Shine

4
我不确定这里发生了什么,但是这对我没有帮助,无论角色如何,任何用户都可以访问该方法。
Urielzen

2
与@Urielzen相同的问题,但已由Jerry Finegan通过以下答案解决(使用“ System.Web.Mvc.AuthorizeAttribute和NOT System.Web.Http.AuthorizeAttribute”)
RJB

13

确保您正在关闭自定义属性类,System.Web.Mvc.AuthorizeAttribute而不是NOT System.Web.Http.AuthorizeAttribute

我遇到了同样的问题。更改后,一切正常。

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

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

我刚刚尝试过,发现引用了System.Web.Http.AuthorizeAttributeINSTEAD OF 图书馆System.Web.Mvc.AuthorizeAttribute
fraser jordan '18

10

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

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

使用CustomRole一个具有常量字符串的类,如下所示:

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

2
有价值;但这应该是评论;没有答案。
GhostCat

1
简单优雅的解决方案!
Iosif Bancioiu

如果正确实施,您的答案和接受的答案都将触发授权(我在生产Web应用程序中使用了接受的答案)。提出一项修改,以删除有关已接受答案的评论。
埃里克·埃斯基尔德森

3

我所做的是@Tieson中的答案

我对他的回答做了些微调整。而不是字符串。为什么不将其转换为列表?

这是我的答案:

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

一切就绪,现在可以验证角色是否有权访问资源


1

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

由于必须在编译时就知道该字符串,所以为什么不创建一个静态的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...
    }
}

1
该示例不起作用,或者至少不符合您的想法。例如,虽然是新颖的ADMIN_OR_VIEWER,但操作上的角色是多余的,因为Create如果您还没有使用该方法,则将无法使用该方法。ADMIN角色,。在这种情况下VIEWER将永远无法调用Create方法。
约翰·莱德格伦

该解决方案也不能扩展。在某些情况下,您将拥有太多角色且采取不同的行动,因此您不应该创建每种组合
EduLopez
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.