我正在构建的页面在很大程度上取决于AJAX。基本上,只有一个“页面”,每个数据传输都通过AJAX处理。由于浏览器端的过度优化缓存导致奇怪的问题(数据未重新加载),我必须使用POST执行所有请求(也读取) - 这会强制重新加载。
现在我想阻止该页面反对CSRF。使用表单提交,使用Html.AntiForgeryToken()
可以正常工作,但在AJAX请求中,我想我必须手动附加令牌吗?有没有开箱即用的东西?
我目前的尝试看起来像:
我想重用现有的魔法。但是,HtmlHelper.GetAntiForgeryTokenAndSetCookie
是私有的,我不想破解MVC。另一种选择是写一个像
public static string PlainAntiForgeryToken(this HtmlHelper helper)
{
// extract the actual field value from the hidden input
return helper.AntiForgeryToken().DoSomeHackyStringActions();
}
这有点hacky并留下未解决的更大问题:如何验证该令牌?默认验证实现是内部的,并且使用表单字段进行硬编码。我尝试编写一个稍微修改过的ValidateAntiForgeryTokenAttribute
,但它使用的是私有的AntiForgeryDataSerializer
,我真的不想复制它。
此时似乎更容易想出一个自己开发的解决方案,但这确实是重复的代码。
有什么建议如何以聪明的方式做到这一点?我错过了一些完全明显的东西吗?
答案 0 :(得分:10)
您可以使用传统的Html.AntiForgeryToken()
帮助程序在页面的某个位置生成隐藏字段(不一定在表单内)并将其包含在ajax请求中:
var token = $('input[name=__RequestVerificationToken]').val();
$.post(
'/SomeAction', { '__RequestVerificationToken': token },
function() {
alert('Account Deleted.');
}
);
要在服务器端验证它:
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult SomeAction()
{
return View();
}
如果您的网页上有多个令牌,则可能需要指定要包含哪个令牌。由于现有助手生成具有相同名称的隐藏字段,因此难以制作好的选择器,因此您可以将它们放置在跨距中:
<span id="t1"><%= Html.AntiForgeryToken() %></span>
<span id="t2"><%= Html.AntiForgeryToken() %></span>
然后选择相应的令牌:
var token = $('#t1 input[name=__RequestVerificationToken]').val();