【问题标题】:How to send AntiForgeryToken (CSRF) along with FormData via jquery ajax如何通过 jquery ajax 与 FormData 一起发送 AntiForgeryToken (CSRF)
【发布时间】: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的答案之一有关

标签: c# jquery ajax asp.net-mvc asp.net-mvc-5


【解决方案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 的当前代码不起作用,那么这也不起作用。
    猜你喜欢
    • 2014-01-30
    • 2013-05-21
    • 2023-03-03
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 2012-10-11
    • 2017-02-26
    • 1970-01-01
    相关资源
    最近更新 更多