序列化JSON在HTTP请求中的位置及防伪令牌读取问题
问题根因
你当前无法正确读取JSON请求体的核心原因有3个:
- 字节转字符串逻辑错误:你没有用字符编码解码字节数组,而是将每个字节的十进制数值直接转字符串拼接,比如字节
0x7B对应字符{,直接ToString()会得到字符串123,最终结果自然是一串无意义的数字 - 请求流指针偏移:
Request.Form读取操作会将InputStream的读取指针移动到流末尾,后续直接调用Read方法无法读取到任何内容 - 缺少JSON反序列化步骤:你当前直接把整个请求体当作令牌值,没有从JSON结构中提取
__RequestVerificationToken对应的字段值
修复步骤
1. 前端代码调整
提交JSON时需要把防伪令牌加入序列化对象中,示例如下:
$.ajax({ type: "POST", // 如果你不需要头传令牌可以去掉headers参数 // headers: appendVerificationToken(), url: "/OrderSettlement/SessionApplyRatesCancel", // 加入__RequestVerificationToken字段 data: JSON.stringify({ key: data.key, __RequestVerificationToken: "你的防伪令牌值" }), contentType: "application/json", success: function () { // 原有逻辑 } });
2. C#验证过滤器代码调整
需要先重置请求流位置,用正确的编码转字符串,再反序列化提取令牌:
using Newtonsoft.Json.Linq; // 如果你用System.Text.Json可以替换对应命名空间 namespace DispatchCrude.Extensions { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } var httpContext = filterContext.HttpContext; var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName]; // 优先从请求头取令牌 var token = httpContext.Request.Headers["__RequestVerificationToken"]; // 从表单取令牌 if (token == null && httpContext.Request.Form.AllKeys.Contains("__RequestVerificationToken")) { token = httpContext.Request.Form["__RequestVerificationToken"]; } // 从JSON请求体取令牌 if (token == null && httpContext.Request.ContentType == "application/json") { // 重置请求流指针到起始位置 httpContext.Request.InputStream.Position = 0; // 用UTF8编码将流转成字符串 using (var reader = new StreamReader(httpContext.Request.InputStream, System.Text.Encoding.UTF8)) { var jsonBody = reader.ReadToEnd(); // 反序列化JSON提取令牌字段 if (!string.IsNullOrEmpty(jsonBody)) { var jsonObj = JObject.Parse(jsonBody); token = jsonObj.Value<string>("__RequestVerificationToken"); } // 再次重置流位置,避免后续Action的模型绑定读取不到请求体 httpContext.Request.InputStream.Position = 0; } } // 验证令牌 AntiForgery.Validate(cookie != null ? cookie.Value : null, token); } } }
注意事项
- 如果你的项目用
System.Text.Json做序列化,将JObject.Parse替换为对应JsonSerializer解析逻辑即可 - 非JSON类型的请求不会走到JSON解析逻辑,不会影响原有表单、头传令牌的验证逻辑
- 读取完请求体后必须重置流指针位置,否则后续Action接收的参数会为空
内容的提问来源于stack exchange,提问作者John Lord
相关产品推荐
相关产品推荐

