Авторизовать атрибут с несколькими ролями

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

Обычно это будет выглядеть так:

[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 и роль известны во время компиляции.

Ответ 1

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

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

Ответ 2

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

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

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

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

Ответ 3

Лучший и самый простой способ, который я нашел для решения этой проблемы, это просто объединить роли в атрибуте Authorize.

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

с CustomRole класс с постоянными строками вроде этого:

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

Ответ 4

Что я сделал, так это ответ в @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);
            }
        }

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

Ответ 5

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

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

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

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

И тогда вы можете использовать атрибут авторизации, например, в классе контроллера или методе контроллера (или обоих):

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

Ответ 6

То, что делает ответ Tieson, просто так =

[Authorize (Roles = "Role1, Role2")]

проверено, работает.