Как написать обработчик асинхронной политики, внедряющий службу с заданной областью действия - PullRequest
0 голосов
/ 28 мая 2020

Я пытаюсь написать настраиваемую политику для ASP. NET веб-приложения Core 3.1, используя настраиваемый поставщик хранилища идентификационных данных.

Я попытался осмыслить этот факт эти политики в ASP. NET Core предназначены для получения пользовательской информации из объекта HttpContext, когда я читаю это в статье MSDN :

после того, как вы содержать ссылку на пользователя, вы всегда можете найти имя пользователя в заявках и выполнить запрос к любой базе данных или внешней службе

Я начал писать свою собственную политику (на данный момент это простое требование роли) вставка UserManager в конструктор:

public class RoleHandler : AuthorizationHandler<RoleRequirement>
{
    private UserManager<AppUser> UserManager;

    public RoleHandler(UserManager<AppUser> usermanager)
    {
        UserManager = usermanager;
    }
}

Теперь у меня есть пара проблем:

ВНЕДРЕНИЕ ОБЪЯВЛЕННОЙ СЛУЖБЫ В ОДНОМ СЛУЧАЕ

Предполагается, что политики действуют в течение всего срока службы приложения, так что это будет Singleton:

services.AddSingleton<IAuthorizationHandler, RoleHandler>();

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

services.AddScoped<IAuthorizationHandler, RoleHandler>();

, но я не знаю, вызывает ли это какие-либо проблемы или нет.

НАПИСАНИЕ АСИНХРОННОГО ОБРАБОТЧИКА ПОЛИТИКИ

Это моя реализация метода HandleRequirementAsync:

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
    AppUser user = UserManager.FindByIdAsync(context.User.Identity.Name).Result;

    if (user != null)
    {
        bool result = UserManager.IsInRoleAsync(user, requirement.Role.ToString()).Result;
        if (result) context.Succeed(requirement);
    }

    return Task.CompletedTask;
}

Я использовал Task.Result, но он блокирует поток. Я не могу использовать await, потому что это заставит метод возвращать Task<Task> вместо Task, и я не могу его изменить. Как я могу это решить?

1 Ответ

2 голосов
/ 28 мая 2020

Не возвращать Task.CompletedTask.

Когда вы объявляете метод как async, он неявно возвращает Task при попадании первого await:

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
    AppUser user = await UserManager.FindByIdAsync(context.User.Identity.Name);

    if (user != null)
    {
        bool result = await UserManager.IsInRoleAsync(user, requirement.Role.ToString());
        if (result) context.Succeed(requirement);
    }
}

Task.CompletedTask обычно используется, когда вам нужно реализовать метод Task, возвращающий синхронно, чего вы не делаете.

...