Bind注解无法阻止Overposting问题排查及解决方案咨询
解决ASP.NET Core中[FromBody]与[Bind]结合防Overposting失效的问题
你碰到的问题确实是**[FromBody]和[Bind]无法协同工作**导致的——这俩属性的作用场景完全不同,一起用的时候[Bind]的白名单规则会被直接忽略。
为什么原来的方法不生效?
在ASP.NET Core里:
[Bind]是给**模型绑定(Model Binding)**用的,针对的是表单数据、查询字符串、路由参数这类来源的绑定,它的白名单规则只在这些场景下生效。[FromBody]则是通过**输入格式化器(Input Formatter)**处理请求体(比如JSON),直接用序列化器(比如Newtonsoft.Json或System.Text.Json)把请求体反序列化成目标对象,这个过程完全绕开了模型绑定的规则,所以你加的[Bind]根本没起作用,JSON里的ClaimAmount还是会被反序列化到Claim对象里。
推荐的解决方案:使用DTO(数据传输对象)
这是防Overposting的最佳实践,通过创建一个只包含允许修改字段的DTO,从根源上避免多余字段被绑定。
步骤1:定义SaveClaimDto
创建一个专门用于这个接口的DTO,只暴露你允许客户端修改的字段:
public class SaveClaimDto { public int WarrantyId { get; set; } public int ClaimId { get; set; } // 若无需修改ClaimId,可设为可空或直接移除 }
步骤2:修改接口接收DTO
把接口的参数换成DTO,再手动映射到你的Claim实体:
[HttpPost, HttpPut] [Route("/Claim/Save")] public async Task<EntitiesCorporation.Model.Claim> Save([FromBody] SaveClaimDto claimDto) { // 初始化Claim实体,仅赋值允许修改的字段 var claim = new EntitiesCorporation.Model.Claim { WarrantyId = claimDto.WarrantyId, ClaimId = claimDto.ClaimId // 其他字段保持默认值,若为更新场景,建议从数据库获取原实体后再覆盖允许修改的字段 }; return await _claimService.SaveClaim(claim, await _userService.GetCurrentUserRecordFromDatabase()); }
步骤3:调整测试代码
测试时即使请求中带了ClaimAmount,由于DTO没有这个字段,反序列化时会直接忽略:
[Theory] [InlineData(1, 34464, "/Claim/Save")] public async Task Save_Claim_Ignores_Overposting(int warrantyId, int claimAmount, string url) { var claimDto = new SaveClaimDto() { WarrantyId = warrantyId, }; var content = JsonConvert.SerializeObject(new { WarrantyId = warrantyId, ClaimAmount = claimAmount }); var response = await _client.PostAsync(url, new StringContent(content, Encoding.UTF8, "application/json")); response.EnsureSuccessStatusCode(); var claimResponse = JsonConvert.DeserializeObject<EntitiesCorporation.Model.Claim>(await response.Content.ReadAsStringAsync()); Assert.True(claimResponse.ClaimAmount == 0); // 现在这个断言会正常通过 }
其他可选方案(不推荐)
如果实在不想用DTO,你可以在JSON序列化器里配置过滤字段,但这种方式耦合性高、灵活性差:
- 对于Newtonsoft.Json,给Claim实体的
ClaimAmount加[JsonIgnore],但会导致所有JSON序列化场景都忽略该字段,可能影响其他接口。 - 自定义
ContractResolver动态过滤字段,但实现复杂,维护成本高。
相比之下,DTO的方式更清晰、安全,也更符合SOLID原则,能从根源上避免Overposting问题。
内容的提问来源于stack exchange,提问作者Bluebaron
相关产品推荐
相关产品推荐

