Передача параметров в Требование/Политика в ASP.NET MVC 6

Я пытался создать собственный атрибут авторизации в ASP.NET vNext, пока не нашел этот отличный ответ от @blowdart в этом сообщении:

qaru.site/info/42950/...

указав, что теперь требования авторизации - это путь. Ответ очень проясняет, но не указывает, как передать параметр этим требованиям/политикам.

То, что я пытаюсь сделать, это портирование атрибута авторизации MVC 5, который имеет эту подпись:

[Autorizacion(Requires = enumPermission.DeleteCustomer)]

так как я использую очень настроенный набор разрешений, зеркально отраженных в backend/frontend как enums/strings.

Поскольку эти функции все еще не документированы, я чувствую себя немного потерянным... Может ли кто-нибудь дать указания?

Заранее спасибо

Ответ 1

Действительно, пост @blowdarts очень проницателен, и из моего понимания ключевое значение для понимания заключается в следующем:

Авторизация действует на Identities. Тождества создаются аутентификации.

Итак, похоже, что идентификаторы создаются процессом аутентификации.

Затем (если хотите) вы можете запустить процесс авторизации. Это означает создание пользовательского authorization requirements, которому это требование будет смотреть на эти тождества и действовать на них.

На простом английском языке это то, что, я считаю, происходит:

  • Как уже упоминалось в postdarts post, у нас должны быть какие-то промежуточное программное обеспечение аутентификации, которое аутентификация. После успешной аутентификации вы берете информацию, которую вы хотите получить от этого пользователя, прошедшего проверку подлинности, и создать аутентифицирован ClaimsPrincipal.

    Например, мы могли бы сохранить в этом ClaimsPrincipal, множества разрешение пользователя.

  • Затем, когда вы создаете свой authorization requirement, вы смотрите на ClaimsPrincipal, извлеките набор разрешений из ClaimsPrincipal и предпринять соответствующие действия на основе бизнес-правила, которые вы хотите.

    Предполагая, что вы не можете хранить наборы разрешений в ClaimsPrincipal по какой-то причине можно было легко сохранить UserId и из этого требования прочитайте, что UserId из ClaimsPrincipal, вызвать базу данных и получить наборы разрешений и затем действовать на них.

Вывод:

Короче говоря, я не думаю, что вы передаете материал требованиям (требованиям), я думаю, что вы получите их из .

В вашем примере вы можете создать требование, которое читает ClaimsPrincipal и сравнивает любое значение с вашим Enum и воздействует на это.

Сообщите нам, что вам удалось сделать, и если оно работает.

И если мое понимание этого неверно, то, во всяком случае, не стесняйтесь исправлять меня, потому что все это новый материал: -)

Ответ 2

Я случайно нашел подходящее решение, которое может удовлетворить мои требования, надеюсь, оно вам тоже поможет.

В моем случае мне нужно передать IHttpContextAccessor и EFCore AppDbContext в мой класс Requirement.

в моем Startup.cs я пишу что-то вроде этого:

services.AddAuthorization(options =>
{
    options.AddPolicy("ThePolicy", policy => policy.Requirements.Add( new ThePolicyRequirement() ));
});
services.AddScoped<IAuthorizationHandler, ThePolicyAuthorizationHandler>();

класс ThePolicyAuthorizationHandler:

public class ThePolicyAuthorizationHandler : AuthorizationHandler<ThePolicyRequirement>
{
    readonly AppDbContext _appContext;
    readonly IHttpContextAccessor _contextAccessor;

    public ThePolicyAuthorizationHandler(AppDbContext c, IHttpContextAccessor ca)
    {
        _appContext = c;
        _contextAccessor = ca;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ThePolicyRequirement requirement)
    {
        var result = await requirement.isPass(_appContext, _contextAccessor, context);
        if (result)
            context.Succeed(requirement);
        else
            context.Fail(requirement);
    }
}

и класс ThePolicyRequirement:

public class ThePolicyRequirement : IAuthorizationRequirement
{
    AppDbContext _context;
    IHttpContextAccessor _contextAccessor;
    AuthorizationHandlerContext _authHandlerContext;

    public async Task<bool> isPass(AppDbContext context, IHttpContextAccessor contextAccessor, AuthorizationHandlerContext authorizationHandlerContext)
    {
        _context = context;
        _contextAccessor = contextAccessor;
        _authHandlerContext = authorizationHandlerContext;

        //logic here

        return result;
    }
}

Ключевая идея заключается в использовании ThePolicyAuthorizationHandler для получения как можно большего количества всех необходимых объектов и передачи его в ThePolicyRequirement для выполнения логики механизма авторизации.