ASP.NET Core MVC中通过AJAX发送AntiForgeryToken的正确方式
问题分析与修正方案
原代码核心缺陷
- 冗余表单令牌:顶部
Html.BeginForm生成的令牌未被使用,属于无效代码。 - 令牌API调用错误:
AntiForgery.GetTokens是旧版API,ASP.NET Core中需注入IAntiforgery服务调用,直接静态调用会报“当前上下文不存在该方法”。 - DOM取值错误:用
innerText获取input值,正确方式是读取value属性。 - JavaScript语法错误:
realdata对象用分号分隔属性,AJAX的headers未用对象格式包裹。 - 未阻止表单默认提交:点击submit会同时触发普通POST和AJAX请求,页面刷新会中断AJAX。
- 令牌选择器错误:
getFormToken中的选择器多了冗余反引号,无法正确匹配令牌元素。
正确实现方式(兼容默认[ValidateAntiForgeryToken])
ASP.NET Core的[ValidateAntiForgeryToken]默认支持两种验证逻辑:
- 表单数据中包含
__RequestVerificationToken字段 - 请求头携带
RequestVerificationToken,同时浏览器自动发送对应防伪Cookie(同域请求默认携带)
推荐用请求头方式,更简洁且不污染表单数据,具体实现如下:
步骤1:注入并获取防伪令牌
在视图中注入IAntiforgery服务,生成合法令牌:
@inject IAntiforgery Antiforgery @{ var tokenSet = Antiforgery.GetAndStoreTokens(Context); var requestToken = tokenSet.RequestToken; }
步骤2:修正JavaScript逻辑
- 阻止表单默认提交行为
- 正确读取输入值
- 在AJAX请求头中携带令牌
- 修复语法错误
步骤3:清理冗余代码
移除无用的Html.BeginForm块,保留必要的令牌生成逻辑。
修正后的完整代码
Razor视图代码
@{ ViewData["Title"] = "Kiosk"; } @model YourNamespace.CodeModel @inject IAntiforgery Antiforgery @{ // 自动生成并存储防伪Cookie,同时获取请求令牌 var tokenSet = Antiforgery.GetAndStoreTokens(Context); } <h1>Check-in Kiosk</h1> <title>@ViewData["Title"]</title> <h2>Follow the instructions below.</h2> <p id="instructions" style="color: green;"> Slide your ID card into the card-holder and wait for further instructions. </p> <div id="row"> <div class="col-md-4"> <form method="post" onsubmit="getData(event)"> <div asp-validation-summary="All" class="text-danger pb-2" id="errors"></div> <div class="form-floating pb-2"> <input asp-for="ScannedCode" class="form-control" id="scancode"/> <label asp-for="ScannedCode"></label> <span asp-validation-for="ScannedCode" class="text-danger"></span> </div> <div class="form-floating pb-2"> <input asp-for="Number" class="form-control" id="number"/> <label asp-for="Number"></label> <span asp-validation-for="Number" class="text-danger"></span> </div> <div class="form-group pt-4"> <input type="submit" class="btn btn-primary" /> </div> </form> </div> </div> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <script> function getData(event) { // 阻止表单默认提交,避免页面刷新 event.preventDefault(); let scannedCode = document.getElementById("scancode").value; let number = document.getElementById("number").value; sendData(scannedCode, number); } function sendData(scannedCode, number) { let realdata = { ScannedCode: scannedCode, Number: number }; $.ajax({ type: "POST", url: "@Url.Action("Index", "Kiosk")", data: realdata, dataType: 'json', headers: { 'RequestVerificationToken': '@tokenSet.RequestToken' }, success: function (response) { document.getElementById("instructions").innerText = response.message; setTimeout(function () { location.reload(); }, response.seconds); }, error: function() { document.getElementById("instructions").innerText = "请求失败,请重试"; } }); } </script>
后端代码(无需修改)
[HttpPost] [ValidateAntiForgeryToken] public IActionResult Index([Bind("ScannedCode,Number")] CodeModel input) { // 业务逻辑实现 }
关键说明
IAntiforgery.GetAndStoreTokens(Context)会自动生成并设置防伪Cookie(.AspNetCore.Antiforgery.xxx),浏览器同域请求时会自动携带该Cookie。- AJAX只需在请求头中携带
RequestVerificationToken,[ValidateAntiForgeryToken]会自动验证Cookie与请求令牌的匹配性。 - 若偏好表单字段方式,可在
realdata中添加__RequestVerificationToken: '@tokenSet.RequestToken',无需设置请求头,验证效果一致。
内容的提问来源于stack exchange,提问作者KingPin SV
相关产品推荐
相关产品推荐

