是否可以将要内联使用的实现传递给ModelBinder?
给出以下定义:
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类可以访问SomeBinder的BindModelAsync方法中所请求的实现: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;
}
答案 0 :(得分:2)
使用泛型。
public class SomeBinder<TConcreteType> : IModelBinder
{
}
然后您的签名成为
public ActionResult InterfaceWithInlineImplementation(
[ModelBinder(typeof(SomeBinder<SomeInterfaceImpelemtation_One>))]ISomeInterface SomeInterface)
然后反序列化是:
JsonConvert.DeserializeObject<TConcreteType>(json)
不过,根据您的最新评论,听起来您只需要Prevent overposting即可,而不是这种复杂的模型绑定。
因此,可以说客户端知道服务器实现具有安全方法,并尝试匹配签名,以希望例如对所有内容进行反序列化。它对您的期望是明确的。而且您明确地只期望合同的定义而已。
节选:
质量分配通常在模型绑定过程中作为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中可以使用的方法相同。我将在这里介绍您的许多选择。