ActionFilter для изменения объявленных значений не влияет на модель - PullRequest
0 голосов
/ 22 февраля 2019

Мы пытаемся обезопасить опубликованные строковые записи в веб-приложении ASP.NET MVC «глобальным» способом.С моей текущей попыткой я написал фильтр настраиваемых действий и украсил действие публикации своим классом FormPostSanitizer.Идея состоит в том, что мы украсим все действия после публикации, которые должны быть продезинфицированы.

Метод успешно захватывает и дезинфицирует входные данные.Но эти очищенные значения не фиксируются в модели до того, как она будет сохранена в базе данных.

Вот как она украшает контроллер.

[HttpPost]
[ValidateAntiForgeryToken]
[FormPostSanitizer]
public ActionResult MyAction(MyViewModel model)
{
    // If ModelState.IsValid, save the model ...
}

Вот мой фильтр действий.

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    if (filterContext.HttpContext.Request.HttpMethod != "POST") return;

    FormCollection formCollection = new FormCollection(filterContext.Controller.ControllerContext.HttpContext.Request.Form);
    foreach (string key in formCollection.AllKeys)
    {
        string sanitized = formCollection[key].SanitizeString(); // Extension method to alter the string.
        formCollection.Set(key, sanitized);
    }
    filterContext.ActionParameters["form"] = formCollection;
}

Я ожидал, что последняя строка передаст измененные значения в filterContext, а модель будет иметь очищенные значения.Значения очищаются, но они не применяются к модели.

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

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Вы должны использовать пользовательский механизм связывания модели, такой как Alexandar, описанный выше, поскольку атрибут фильтра действия выполняется после того, как модель уже привязана, и вы не можете изменить его в данный момент.Если вы сделаете это в связывателе модели, то она будет применена к модели, как вы ожидаете

0 голосов
/ 22 февраля 2019

Для этой цели вы можете создать пользовательское связующее для модели

public class SanitizeModelBinder : DefaultModelBinder
{
    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
    {
        bool sanitize = controllerContext.HttpContext.Request.HttpMethod == "POST";

        //get value from default binder
        object value = base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
        if (!sanitize)
        {
            return value;
        }

        //sanitize value if it is a string
        string stringValue = value as string;
        if (stringValue != null)
        {
            return stringValue.SanitizeString();
        }

        return value;
    }
}

Установить связующее по умолчанию в Global.asax.cs, чтобы использовать его для каждого действия

System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new SanitizeModelBinder();

или, если вы хотите использовать этосвязующее для некоторых моделей

public ActionResult MyAction([ModelBinder(typeof(SanitizeModelBinder))]MyViewModel model)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...