#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 или нет.