Как вызвать обработчик сохраненного запроса предыдущего запроса из фильтра для страниц Razor?

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

Вопрос:

У меня есть следующий класс фильтров страниц razor:

 public class TwoFactorPageFilter : IAsyncPageFilter
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly ApplicationSession _session;
    private HttpContext _httpContext;

    public TwoFactorPageFilter(UserManager<IdentityUser> userManager, ApplicationSession session)
    {
        _userManager = userManager;
        _session     = session;
    }

    public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext pageContext)
    {
        await Task.CompletedTask;
    }

    public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext pageContext, PageHandlerExecutionDelegate next)
    {
        _httpContext = pageContext.HttpContext;

        await InitTwoFactorLock();

        if ( RequestRequires2fa() )
        {
            SavePostActionState(pageContext);
            _httpContext.Response.Redirect("/Identity/Account/LoginWith2fa");
        }
        else if ( _session.Recent2fa )
        {
            // HELP: how to call original razor page handler here, using properties
            // saved to _session, after user successfully verified using 2FA?
        }

        await next.Invoke();
    }

    private async Task InitTwoFactorLock()
    {
        IdentityUser user = await _userManager.GetUserAsync(_httpContext.User);
        // initialize the 2FA lock default value based on if the user enabled/disabled 2FA login
        _session.TwoFactorLockOn = user is not null ? await _userManager.GetTwoFactorEnabledAsync(user) : false;
    }

    private bool RequestRequires2fa()
    {
        // only POST requests would ever need to be verified
        if ( _httpContext.Request.Method != "POST" ) return false;

        // don't bother if user is not even authenticated
        if ( ! _httpContext.User.Identity.IsAuthenticated) return false;

        // if the 2FA lock session variable is turned off, then do not require 2FA verification
        if ( ! _session.TwoFactorLockOn ) return false;

        return RouteNeeds2fa();
    }

    private bool RouteNeeds2fa()
    {
        var paths = new List<string> {"/Account/Change", "/Account/Remove", "/Security/Update",};
        return paths.Contains(_httpContext.Request.Path);
    }

    private void SavePostActionState(PageHandlerExecutingContext pageContext)
    {
        // save all relevant data to session state
        _session.OriginalHandlerMethod = pageContext.HandlerMethod;
        _session.OriginalModelState    = pageContext.ModelState;
        // HELP: what else do I need to save to the session state here?
    }

}
 

Идея состоит в том, чтобы перенаправлять POST запросы, попадающие на определенные маршруты/конечные точки, на страницу проверки 2FA вместо этого для повышения безопасности. Часть перенаправления в настоящее время работает достаточно хорошо.

Я бы хотел, чтобы это сработало, чтобы сохранить состояние обработчика запроса (т. Е. SavePostActionState ) в _session (реализацию ISession ), когда поступает исходный POST запрос и перенаправляется на /Identity/Account/LoginWith2fa конечную точку. Затем, когда пользователь успешно пройдет проверку с помощью своего аутентификатора 2FA, _session.Recent2fa true в обработчике LoginWith2fa страницы будет установлено значение, и я получу сохраненную информацию о состоянии обработчика для исходного запроса, отправленного пользователем, и выполню это действие.

Но , учитывая свойства/объекты, доступные мне через PageHandlerExecutedContext , такие как HandlerInstance , HandlerMethod , ModelState Result , и т. Д. Я все еще не уверен в том, как их составить, чтобы «повторно вызвать» исходный запрос.

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

1. Как бы вы обрабатывали запросы на публикацию с большими объемами? Прочитать и сохранить поток запросов в памяти? Вы должны прочитать тело, иначе оно будет потеряно. Я думаю, вам было бы лучше все упростить: сохранить состояние в пользовательском интерфейсе, выполнить 2FA во всплывающем окне, если вы не хотите потерять состояние формы. Если это удастся, то выполните фактический запрос

2. @abdusco хорошо говорит о больших телах, хотя в текущей области применения это вряд ли будет проблемой, b/c все данные, опубликованные пользователем, проверяются на меньший, чем скромный размер. То, как вы предлагаете, более или менее соответствует тому, как это работает в настоящее время. Однако это привело к довольно большому количеству дублированного кода в каждом обработчике для всех действий, требующих этого шага проверки 2FA, и в противном случае ненужных зависимостей в их соответствующих PageModel классах. Также с точки зрения бизнес-логики имеет больше смысла, чтобы этим действиям не нужно было беспокоиться о том, следует ли им проверять 2FA или нет.