Проверка одной из нескольких политик с атрибутом авторизации в ASP.NET Core Identity

Я установил стандартную систему аутентификации в приложении ASP.NET Core.

Пользователи, роли, RoleClaims (действующие как разрешения)

В Startup.cs я создаю политику для каждой роли и каждого разрешения. Предполагая, что это дало бы мне полную гибкость в моих представлениях, чтобы я мог сказать, что я хочу, чтобы эта кнопка показывала, является ли пользователь частью роли, которая имеет требование DeleteCustomer, или если пользователь принадлежит роли суперпользователя.

Как я могу выполнить условие ИЛИ с помощью атрибута Authorize. Например, на всем моем сайте я хочу, чтобы политика SuperuserRole имела полное разрешение на все.

Допустим, у меня есть следующий метод действия:

[Авторизоваться (Политика = "EditCustomer")]

Это потребует, чтобы вошедшему в систему пользователю была назначена роль с утверждением: Edit.Customer, поскольку я создаю политику для утверждения Edit.Customer. Все это работает нормально, но как я могу сказать, что я бы хотел, чтобы любой пользователь с ролью суперпользователя имел доступ к методу действия EditCustomer. Суперпользователь находится в базе данных как роль и дополнительно добавляется как политика под названием RequireSuperUser.


person Blake Rivell    schedule 09.11.2017    source источник
comment
У вас это сработало? Я столкнулся с аналогичной проблемой. Ответ @Richard Mneyan получил мой голос и работал на меня. Было бы хорошо получить на это ответ, так как это поможет другим.   -  person Bronumski    schedule 19.02.2018


Ответы (3)


Вы можете добавить условие ИЛИ в Startup.cs:

services.AddAuthorization(options => {
    options.AddPolicy("EditCustomer", policy =>
        policy.RequireAssertion(context => 
        context.User.HasClaim(c => (c.Type == "DeleteCustomer" || c.Type == "Superuser"))));
});

Я столкнулся с аналогичной проблемой, когда я хотел, чтобы только пользователи «Джон Доу», «Джейн Доу» могли просматривать экран «Завершение контрактов» ИЛИ кто-либо только из отдела «MIS» также имел доступ к тому же экрану. Для меня сработало следующее, где у меня есть типы претензий «отдел» и «имя пользователя»:

services.AddAuthorization(options => {
    options.AddPolicy("EndingContracts", policy =>
        policy.RequireAssertion(context => context.User.HasClaim(c => (c.Type == "department" && c.Value == "MIS" ||
        c.Type == "UserName" && "John Doe, Jane Doe".Contains(c.Value)))));
});
person Richard Mneyan    schedule 09.02.2018
comment
Отлично, спасибо! Любой, кто попадает сюда и проходит аутентификацию с использованием ролей Azure, может использовать что-то вроде: policy.RequireAssertion (context = ›context.User.HasClaim (ClaimTypes.Role, Analyst) || context.User.HasClaim (ClaimTypes.Role, Reader)) - person fuzzy_logic; 01.11.2018

Вы можете использовать два разных обработчика AuthorizationHandler с одинаковым требованием IAuthorizationRequirement:

public class FooOrBooRequirement : IAuthorizationRequirement { }

public class FooHandler : AuthorizationHandler<FooOrBooRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationContext context, FooOrBooRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "Foo" && c.Value == true))
        {
            context.Succeed(requirement);
            return Task.FromResult(0);
        }
    }
}

public class BooHandler : AuthorizationHandler<FooOrBooRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationContext context, FooOrBooRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "Boo" && c.Value == true))
        {
            context.Succeed(requirement);
            return Task.FromResult(0);
        }
    }
}

Таким образом, в AddPolicy у вас будет только одно требование, которое может быть выполнено FooHandler или BooHandler:

services.AddAuthorization(authorizationOptions =>
{
    authorizationOptions.AddPolicy(
        "MustBeFooOrBoo",
        policyBuilder =>
        {
            policyBuilder.RequireAuthenticatedUser();
            policyBuilder.AddRequirements(new FooOrBooRequirement());
        });
});

Обратите внимание, что AuthorizationHandler предоставляет более мощную настраиваемую политику, поэтому она наиболее актуальна только для особых случаев, требующих более сложной аутентификации, например, если вы хотите определить, является ли пользователь владельцем ресурса.

Для простой политики, основанной на утверждениях, я бы посоветовал использовать ответ @ richard-mneyan.

person Shahar Shokrani    schedule 30.06.2020

Мы можем внедрить DBContext (если используется EF или пользовательский репозиторий, если нет) или HttpContextAccessor в AuthorizationHandler, чтобы добиться этого.

Внедряя EF Context (или пользовательский репозиторий), мы можем запросить базу данных, чтобы выяснить, является ли текущий пользователь суперпользователем.

Или, введя HttpContextAccessor, мы можем определить, является ли пользователь суперпользователем. Этот подход работает быстрее, чем первый, но зависит от того, имеет ли пользовательский контекст необходимую информацию или нет.

Для этого, если у вас есть EditCustomerRequirement и EditCustomerAuthorizationHandler:

public class EditCustomerAuthorizationHandler: AuthorizationHandler<EditCustomerRequirement>
{
     readonly AppDbContext _context;
     readonly IHttpContextAccessor _contextAccessor;

     public EditCustomerAuthorizationHandler(DbContext c, IHttpContextAccessor ca)
     {
         _context = c;
         _contextAccessor = ca;
     }

     protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, EditCustomerRequirement requirement)
     {
         //here we have the access to DB and HttpContext
         //we can get the information if the user is superuser from either db or httpContext 
         var isSuperUser = await IsSuperUser(_context);
         //or
         var isSuperUser = IsSuperUser(_contextAccessor);
         if(isSuperUser) 
         {
             context.Succeed(requirement);
         }
         else
         {
            //the current implementation of EditCustomer Policy
         }
     }
}

IsSuperUser - это своего рода метод, который мы могли бы создать для получения информации из контекста базы данных или контекста http.

person Riza    schedule 14.12.2020