Модель WebAPI [ModelBinder] с классом интерфейса при указании реализации - PullRequest
1 голос
/ 28 марта 2019

Можно ли передать в ModelBinder, какую реализацию вы хотите использовать inline?

С учетом следующих определений:

public interface ISomeInterface
{
    string MyString{get;set;}
}

public class SomeInterfaceImplementation_One : ISomeInterface
{
    private string _MyString;

    public string MyString
    {
       get {return "This is implementation One " + _MyString ; }
       set { _MyString = value;  }
    }
}

public class SomeInterfaceImplementation_Two : ISomeInterface
{
    private string _MyString;

    public string MyString
    {
       get {return "This is implementation Two" + _MyString ; }
       set { _MyString = value;  }
    }
}

Данный маршрут в ядре asp.net mvc:

public ActionResult InterfaceWithInlineImplementation([ModelBinder(typeof(SomeBinder))]ISomeInterface SomeInterface)
{
       //Return actionresult
}

Мне не нужен отдельный класс ModelBinder для каждой реализации, а хотелось бы, чтобы каждый маршрут указывал, какая реализация встроена.

Так что-то вроде:

[UseImplementation(SomeInterfaceImplementation_One)]
public ActionResult InterfaceWithInlineImplementation([ModelBinder(typeof(SomeBinder))]ISomeInterface SomeInterface)
{

}

Или:

 public ActionResult InterfaceWithInlineImplementation([ModelBinder(typeof(SomeBinder), ConcreteType = SomeInterfaceImplementation_Two )]ISomeInterface SomeInterface)
    {

    }

Таким образом, класс SomeBinder может получить доступ к тому, какая реализация запрашивается в методе BindModelAsync класса SomeBinder: IModelBinder.

public class SomeBinder : Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinder
    {

        public Task BindModelAsync(Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));

            string valueFromBody = string.Empty;

            using (var sr = new StreamReader(bindingContext.HttpContext.Request.Body))
            {
                valueFromBody = sr.ReadToEnd();
            }

            if (string.IsNullOrEmpty(valueFromBody))
            {
                return Task.CompletedTask;
            }

            var settings = new JsonSerializerSettings()
            {
                ContractResolver = new InterfaceContractResolver(), // Need requested implementation from InterfaceWithInlineImplementation() method

            }; 

            var obj = JsonConvert.DeserializeObject(valueFromBody, [**Need Requested Implementation from Method**], settings);
            bindingContext.Model = obj;


            bindingContext.Result = ModelBindingResult.Success(obj);


            return Task.CompletedTask;
        }

1 Ответ

2 голосов
/ 28 марта 2019

Используйте дженерики.

public class SomeBinder<TConcreteType> : IModelBinder
{
}

Тогда ваша подпись становится

public ActionResult InterfaceWithInlineImplementation(
  [ModelBinder(typeof(SomeBinder<SomeInterfaceImpelemtation_One>))]ISomeInterface SomeInterface)

Тогда десериализация будет:

JsonConvert.DeserializeObject<TConcreteType>(json)

Однако, исходя из вашего последнего комментария, звучит так, как будто вам просто нужно Предотвратить перепост вместо этой запутанной привязки модели.

Итак, предположим, что клиент знает, что у реализации сервера есть методы безопасности, и пытается сопоставить сигнатуру, надеясь, что все, к примеру, будет десериализировано. Ясно, что вы ожидаете. И вы явно ожидаете только определения контракта и ничего более.

Выдержка:

Массовое присвоение обычно происходит во время связывания модели как часть MVC. Простой пример: на вашем веб-сайте есть форма, в которой вы редактируете некоторые данные. У вас также есть некоторые свойства в вашей модели, которые нельзя редактировать как часть формы, но вместо этого они используются для управления отображением формы или могут вообще не использоваться.

public class UserModel
{
  public string Name { get; set; }
  public bool IsAdmin { get; set; }
}

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

[HttpPost]
public IActionResult Vulnerable(UserModel model)
{
    return View("Index", model);
}

Однако, с помощью простых манипуляций с HTML или с помощью Postman / Fiddler, злоумышленник может установить для поля IsAdmin значение true. Связыватель модели должным образом свяжет значение, и вы только что стали жертвой массового назначения / повторного размещения:

Так как вы можете предотвратить эту атаку? К счастью, существует целый ряд различных способов, и они, как правило, совпадают с подходами, которые вы могли использовать в предыдущей версии ASP.NET. Здесь я рассмотрю ряд ваших вариантов.

Перейти к статье ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...