请求参数安全也是需要我们考虑的因素,比如如下我们对象包含IsAdmin属性,我们后台会根据该属性值判断是否为对应角色进行UI的渲染,我们可以通过[Bind]特性应用于对象指定映射哪些属性,此时请求中参数即使显式指定了该参数值也不会进行映射(这里仅仅只是举例说明,例子可能并非合理),代码如下:
public class Customer { public int Id { get; set; } public int Age { get; set; } public string Address { get; set; } public bool IsAdmin { get; set; } } [Route("[controller]")] public class ModelBindController : Controller { [HttpPost] public IActionResult Post( [Bind(nameof(Customer.Id),nameof(Customer.Age),nameof(Customer.Address) )] Customer customer) { if (!ModelState.IsValid) { return BadRequest(ModelState); } return Ok(); } }
来源绑定
在.NET Core中出现了不同的特性,比如上述我们所讲解的行为绑定,然后是接下来我们要讲解的来源绑定,它们出现的意义和作用在哪里呢?它比.NET中的模型绑定更加灵活,而不是一样,为何灵活不是我嘴上说说而已,通过实际例子证明给你看,每一个新功能或特性的出现是为了解决对应的问题或改善对应的问题,首先我们来看如下代码:
[Route("[controller]")] public class ModelBindController : Controller { [HttpPost("{id:int}")] public IActionResult Post(int id, Customer customer) { if (!ModelState.IsValid) { return BadRequest(ModelState); } return Ok(); } }
我们通过路由指定id为4,然后url上指定为3,你猜映射到后台id上的参数结果是4还是3呢,在customer上的参数id是4还是3呢?
从上图我们看到id是4,而customer对象中的id值为2,我们从中可以得出一个什么结论呢,来,我们进行如下总结。
在.NET Core中,默认情况下参数绑定存在优先级,路由的优先级大于表单的优先级,表单的优先级大于URL的优先级即(路由>表单>URL)
这是默认情况下的优先级,为什么说在.NET Core中非常灵活呢,因为我们可以通过来源进行显式绑定,比如强制指定id来源于查询字符串,而customer中的id源于查询路由,如下:
[HttpPost("{id:int}")] public IActionResult Post([FromQuery]int id, [FromRoute] Customer customer) { if (!ModelState.IsValid) { return BadRequest(ModelState); } return Ok(); }
还有什么[FromForm]、[FromServices]、[FromHeader]等来源绑定都是强制指定参数到底是来源于表单、请求头、查询字符串、路由还是Body,到这里无需我再过多讲解了,一个例子足以说明其灵活性。
模型绑定(强大支持举例)
上述讲解来源绑定我们认识到其灵活性,可能有部分童鞋压根都不知道.NET Core中对模型绑定的强大支持,哪里强大了,在讲解模型绑定原理之前,来给大家举几个实际的例子来说明,首先我们来看如下请求代码:
对于如上请求,我们大部分的做法则是通过如下创建一个类来接受上述URL参数。
public class Example { public int A { get; set; } public int B { get; set; } public int C { get; set; } } [Route("[controller]")] public class ModelBindController : Controller { [HttpGet] public IActionResult Post(Example employee) { return Ok(); } }
这种常见做法在ASP.NET MVC/Web Api中也是支持的,好了,接下来我们将上述控制器代码进行如下修改后在.NET Core中是支持的,而在.NET MVC/Web Api中是不支持的,不信,您可以试试。
[Route("[controller]")] public class ModelBindController : Controller { [HttpGet] public IActionResult Get(Dictionary<string, int> pairs) { return Ok(); } }
至于在.NE Core中为何能够绑定上,主要是在.NET Core实现了字典的DictionaryModelBinder,所以可以将URL上的参数当做字典的键,而参数值作为键对应的值,看的不过瘾,对不对,好,接下来我们看看如下请求,您觉得控制器应该如何接收URL上的参数呢?
大胆发挥您的想象,在我们的控制器Action方法上,我们如何去接收上述URL上的参数呢?好了,不卖关子了,