Атрибут Authorize с несколькими ролями

Я хотел бы добавить авторизацию к контроллеру для нескольких ролей сразу.

обычно это выглядит так:

[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()
{
}

есть ли способ обойти эту проблему?

Я мог бы написать const, который просто содержит "RoleA, RoleB, RoleC" - но я не люблю Волшебные струны, и это волшебная струна. Изменение имени роли и забывание изменить объединенную строку было бы катастрофой.

Я использую MVC5. ASP.NET идентичность и роль известны во время компиляции.

5 ответов


попробуйте создать пользовательский атрибут авторизации, например этой.

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

убедитесь, что вы выводите свой пользовательский класс атрибутов off System.Web.Mvc.AuthorizeAttribute, а не System.Web.Http.AuthorizeAttribute.

я столкнулся с такой же проблемой. Как только я изменил его, все работало.

вы также можете добавить следующее в свой пользовательский класс атрибутов:

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

не знаю, почему все приняли этот ответ. Я сделал точно так, как упоминалось, и теперь он не делает абсолютно никакой проверки авторизации. Анонимные пользователи теперь могут подключаться к каждому методу, украшенному этим пользовательским атрибутом... Лучший и самый простой способ решить эту проблему - просто объединить роли в атрибуте Authorize.

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

С CustomRole класс с постоянными строками, как это:

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

что я сделал ответ в @стяжек

Я немного подправляю его ответ. Вместо веревки.Присоединиться почему бы не преобразовать его в список?

вот мой ответ:

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

и там у вас есть это, теперь он проверяет, авторизована ли роль для доступа к ресурсу


Я чувствую, что пользовательский атрибут авторизации является излишним для этой проблемы, если у вас нет большого количества ролей.

поскольку строка должна быть известна во время компиляции, почему бы не создать статический класс ролей, содержащий открытые строки определенных вами ролей, а затем добавить строки, разделенные запятыми, с определенными ролями, которые вы хотите авторизовать:

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

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

и затем вы можете использовать атрибут Authorize как в классе контроллера или методе контроллера (или оба):

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