ASP.NET Core中表单提交时生成reCAPTCHA v3 Token的实现问题
解决方案
问题核心是requestSubmit会重新触发submit事件,导致逻辑循环,同时可能丢失防伪造令牌的提交上下文。以下是两种可靠的解决方式:
方式一:修改提交逻辑避免循环
在设置Token后直接调用表单原生的submit()方法,同时添加判断避免重复触发阻止逻辑:
grecaptcha.ready(function() { const contactForm = document.getElementById("contact"); contactForm.addEventListener("submit", function(e) { // 仅当Token为空时,才执行reCAPTCHA获取逻辑 if (!document.getElementById("Token").value) { e.preventDefault(); grecaptcha.execute("@Model.reCaptchaSiteKey", {action: "contact"}).then(function(token) { document.getElementById("Token").value = token; // 调用原生submit,不会再次触发当前的submit监听事件 contactForm.submit(); }); } }); });
这个方法的关键是通过Token是否存在的判断,避免submit()调用后再次进入阻止逻辑,同时原生submit()会自动包含表单内的防伪造令牌。
方式二:使用AJAX手动控制提交过程
如果原生提交仍有问题,可以改用AJAX提交,手动确保防伪造令牌和reCAPTCHA Token都被正确发送:
grecaptcha.ready(function() { const contactForm = document.getElementById("contact"); contactForm.addEventListener("submit", function(e) { e.preventDefault(); grecaptcha.execute("@Model.reCaptchaSiteKey", {action: "contact"}).then(function(token) { document.getElementById("Token").value = token; // 获取页面中的防伪造令牌 const antiforgeryToken = document.querySelector('input[name="__RequestVerificationToken"]').value; // 构造FormData对象,包含所有表单字段 const formData = new FormData(contactForm); // 发送请求 fetch(contactForm.action, { method: contactForm.method, body: formData, headers: { "RequestVerificationToken": antiforgeryToken } }).then(response => { // 处理提交结果 if (response.ok) { // 提交成功后的逻辑,比如跳转成功页 window.location.href = "/contact/success"; } else { alert("提交失败,请稍后重试"); } }).catch(error => { console.error("提交出错:", error); alert("提交出错,请稍后重试"); }); }); }); });
这种方式完全掌控提交流程,确保所有必要的令牌都被正确传递,同时可以更灵活地处理提交结果。
重要注意事项
- 绝对不要禁用防伪造验证:这会引入CSRF攻击风险,必须保留ASP.NET Core的防伪造机制。
- 确保后端验证reCAPTCHA时,使用的action名称和前端
execute方法中指定的一致(这里是contact)。 - 后端模型要正确绑定
Token字段,确保能接收并验证reCAPTCHA Token。
内容的提问来源于stack exchange,提问作者Duke3e33
相关产品推荐
相关产品推荐

