Как проверять / перенаправлять в каждом методе любого контроллера в ASP NET Core 3.1?

#c# #asp.net #asp.net-core #asp.net-core-middleware

#c# #asp.net #asp.net-core #asp.net-core-промежуточное программное обеспечение

Вопрос:

Я ищу способ сделать это в каждом методе каждого контроллера, даже для тех, которые не возвращают IActionResult (я буду говорить об этом в будущем):

  1. Получите User.Claim, чтобы получить информацию о пользователе, зарегистрированную на сайте.
  2. Проверьте, заблокирован ли пользователь в базе данных (у меня уже работают мои собственные репозитории)
  3. Перенаправить пользователя на страницу, которая показывает «вы заблокированы», как это делает рабочий процесс исключений.

Соображения и попытки, которые я уже сделал:

  • Не могу получить это из заявки, чтобы работать с ViewStart, потому что мне нужно, чтобы блок работал в тот же момент, когда база данных была обновлена. Утверждение должно заставить пользователя выйти и войти в систему.
  • Не могу сделать это через контроллер, который возвращает логическое значение с Json на каждой странице, потому что пользователь может остановить перенаправление
  • У меня есть несколько методов, которые возвращают partialviews, objects, lists, что угодно, кроме IActionResult. Мне все равно, если это не сработает по двум причинам:
    • Это должно быть вызвано основным представлением, которое вызывает их через ajax.
    • Пользователь все равно заблокирован, поэтому мне все равно, увидит ли он, что страница сломана.
  • Мой рабочий процесс безопасности выглядит следующим образом:
     [HttpPost]
    [Authorize(Policy = "Users")]
    [Authorize(AuthenticationSchemes = "MyAppScheme")]
    
    public IActionResult GetRep() {
         //Do things
    }
     

Прямо сейчас я пытаюсь создать промежуточное программное обеспечение, но я новичок в NET Core на таком глубоком уровне, поэтому не могу скомпилировать ни то, ни другое. Также работает попытка вызвать мой UserRepository из ViewStart

Комментарии:

1. Почему вы не используете промежуточные программы, которые будут работать глобально в вашем приложении. Фильтр действий был бы лучшим выбором Chekc MS Docs

2. @RabbyHasan спасибо! Да, это то, что я пытаюсь, но не знаю, как это сделать правильно

Ответ №1:

Лучший способ — использовать промежуточное программное обеспечение. Вот вам пример:

 internal class UserMiddleware
{
    private readonly RequestDelegate next;
    private readonly IUserRepository userRepository;

    public UserMiddleware(RequestDelegate next, IUserRepository userRepository)
    {
        this.next = next ?? throw new ArgumentNullException(nameof(next));
        this.userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
    }

    public async Task Invoke(HttpContext httpContext)
    {
        Claim clientId = httpContext.User.FindFirst(ClaimTypes.NameIdentifier);
        bool isBlocked = await this.userRepository.CheckUser(clientId);

        if (isBlocked)
        {
            await httpContext.Response.WriteAsync("You are blocked.");
            return;
        }

        await this.next(httpContext);
    }
}
 

Затем в вашем методе запуска вы должны вызвать его перед отображением ваших контроллеров:

 public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Other stuff...

    app.UseMiddleware<UserMiddleware>();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}
 

Комментарии:

1. Теперь у меня есть несколько проблем с ‘Вторая операция началась в этом контексте до завершения предыдущей операции. Обычно это вызвано тем, что разные потоки используют один и тот же экземпляр DbContext. Для получения дополнительной информации о том, как избежать проблем с потоками с DbContext, см. go.microsoft.com/fwlink/?linkid=2097913 .’

2. Не знаю почему, потому что я делаю обычное user = await _context . Пользователи. Где(u => u.Guid == guid amp;amp; u.Удалено == 0 amp;amp; u.Заблокировано == 0).FirstAsync();