如何通过 jquery ajax 与 FormData 一起发送 AntiForgeryToken (CSRF)
Posted
技术标签:
【中文标题】如何通过 jquery ajax 与 FormData 一起发送 AntiForgeryToken (CSRF)【英文标题】:How to send AntiForgeryToken (CSRF) along with FormData via jquery ajax 【发布时间】:2015-12-23 03:40:56 【问题描述】:所以我想通过 AJAX 将 POST
文件上传和 AntiForgeryToken
一起上传。这是我的代码:
查看
@using (html.BeginForm("Upload", "RX", FormMethod.Post, new id = "frmRXUpload", enctype = "multipart/form-data"))
@Html.AntiForgeryToken()
@Html.TextBoxFor(m => m.RXFile, new .type = "file")
...rest of code here
<script>
$(document).ready(function()
$('#btnRXUpload').click(function ()
var form = $('#frmRXUpload')
if (form.valid())
var formData = new FormData(form);
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
formData.append('__RequestVerificationToken', fnGetToken());
$.ajax(
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
)
)
)
</script>
控制器
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload()
//rest of code here
我明白了
无法解密防伪令牌。如果此应用程序由 Web Farm 或集群托管
通过提琴手出错。知道如何解决这个问题吗?
我找到了答案:
<script>
$(document).ready(function()
$('#btnRXUpload').click(function ()
var form = $('#frmRXUpload')
if (form.valid())
var formData = new FormData(form.get(0)); //add .get(0)
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
$.ajax(
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
)
)
)
</script>
【问题讨论】:
什么是fnGetToken()
?
如果应用程序未托管在 Web Farm 或集群上,此行为是否会改变?非 ajax 请求有效吗?
@StephenMuecke:获取令牌字符串的函数
是的,但它返回了什么?为什么不按照我对您的previous questions 之一的回答使用var formdata = new FormData($('form').get(0));
?
错误消息表明它可能与this question的答案之一有关
【参考方案1】:
终于找到答案了:
我只需要在表单中添加.get(0)
,代码如下:
<script>
$(document).ready(function()
$('#btnRXUpload').click(function ()
var form = $('#frmRXUpload')
if (form.valid())
var formData = new FormData(form.get(0)); //add .get(0)
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
//formData.append('__RequestVerificationToken', fnGetToken()); //remark this line
$.ajax(
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: false,
processData: false
)
)
)
</script>
【讨论】:
【参考方案2】:您需要将令牌添加到请求标头,而不是表单。像这样:
if (form.valid())
var formData = new FormData(form);
formData.append('files', $('#frmRXUpload input[type="file"]')[0].files[0]);
$.ajax(
type: 'POST',
url: '/RX/Upload',
data: formData,
contentType: 'multipart/form-data',
processData: false,
headers:
'__RequestVerificationToken': fnGetToken()
)
编辑
回顾我自己是如何解决这个问题的,我记得标准的 ValidateAntiForgeryTokenAttribute 在 Request.Form 对象中查找,该对象并不总是为 AJAX 请求填充。 (在您的情况下,文件上传需要 multipart/form-data
内容类型,而 CSRF 令牌的表单发布需要 application/x-www-form-urlencoded
。您设置了 contentType=false
,但这两个操作需要冲突的内容类型,这可能是您的一部分问题)。因此,为了验证服务器上的令牌,您需要为您的操作方法编写一个自定义属性,以检查请求标头中的令牌:
public sealed class ValidateJsonAntiForgeryTokenAttribute
: 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];
AntiForgery.Validate(cookie != null ? cookie.Value : null,
httpContext.Request.Headers["__RequestVerificationToken"]);
更多信息(现在有点过时了)here。
【讨论】:
令牌可以添加到FormData
。如果 OP 的当前代码不起作用,那么这也不起作用。以上是关于如何通过 jquery ajax 与 FormData 一起发送 AntiForgeryToken (CSRF)的主要内容,如果未能解决你的问题,请参考以下文章
jquery异步ajax与服务器通信过程中如何通过then方法链式传递多层数据
jquery异步ajax与服务器通信过程中如何通过then方法链式传递多层数据 --转载