简体   繁体   中英

How to send anti forgery token with Ajax file upload?

I'm trying to upload file(s) with an ajax call and validate the anti forgery token. I've had a look around and built a method to validate the anti forgery token on the controller. However whenever I have @Html.AntiForgeryToken on the view, my files do not get populated. Even though it validates the anti forgery token. It doesn't seem to be getting sent with the request but I'm unsure why.

ajaxSendOverride:

$(document).ready(function () {

    var securityToken = $('[name=__RequestVerificationToken]').val();

    $(document).ajaxSend(function (event, request, opt) {
        if (opt.hasContent && securityToken) {   // handle all verbs with content

            var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);

            opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;

            // ensure Content-Type header is present!
            if (opt.contentType !== false || typeof event.contentType !== 'undefined') {
                request.setRequestHeader("Content-Type", opt.contentType);
            }
        }
    });
});

Ajax:

$(document).on("submit", "[data-upload-contract-form]", function (e) {
        e.preventDefault();
        var formData = new FormData($('[data-upload-contract-form]')[0]);
        if ($('[data-upload-file]').val() != "") {
            $.ajax({
                url: $(this).attr('action'),
                data: formData,
                type: 'POST',
                processData: false,
                contentType: false,
                headers: {
                    '__RequestVerificationToken': $('[name=__RequestVerificationToken]').val()
                },
                success: function (data) {
                    if (data.Success === true) {
                        $('[data-contract-error-message]').text();
                        ReturnDataTableForUploadFile($('[data-upload-file-supplier-contract-id]').val());
                        table.ajax.reload();
                    }
                    else {
                        $('[data-contract-error-message]').show();
                        $('[data-contract-error-message]').text(data.ResponseText);
                    }
                }
            })
            .fail(function () {
                $('[data-contract-error-message]').show();
                $('[data-contract-error-message]').text("Something went wrong uploading your file, please try again.");
            });
        }
        else {
            $('[data-contract-error-message]').show();
            $('[data-contract-error-message]').text("No contract to upload");
        }
    });

Validation:

 public sealed class AuthorizeAntiForgeryToken : System.Web.Mvc.FilterAttribute, System.Web.Mvc.IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            var httpContext = filterContext.HttpContext;
            var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
            AntiForgery.Validate(cookie != null ? cookie.Value : null,
                                 httpContext.Request.Headers["__RequestVerificationToken"]);
        }
    }

Controller:

 public async Task<JsonResult> UploadContract(UploadContract model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    foreach (var item in model.Contracts)
                    {
                        string filePath = WebConfigurationManager.AppSettings["SupplierContractPath"] + GetSelectedClientId() + "\\" + item.FileName;

                        _supplierFileManager.UploadFile(item, filePath);

                        await _supplierFileManager.SaveContractToDatabase(model.SupplierContractID, item.FileName);
                    }
                    return Json(new { Success = true });
                }
                catch (Exception e)
                {
                    return Json(new { Success = false, ResponseText = e.Message });
                }
            }
            else
            {
                string errorMessage = "";
                foreach (var item in ModelState.Values.SelectMany(r => r.Errors))
                {
                    errorMessage += "<p>" + item.ErrorMessage + "</p>";
                }
                return Json(new { Success = false, ResponseText = errorMessage });
            }
        }

How can I send my files with the anti forgery token?

I ran into this problem myself today and ran into this question without an answer. The links to other answers didn't work, but after a while I found the solution.

The anti-forgery token has to be in a form field, not a header. It also has to be the first field in the form data. So to solve it, do:

$(document).on("submit", "[data-upload-contract-form]", function (e) {
        e.preventDefault();
        var formData = new FormData();
        formData.append('__RequestVerificationToken', $('[name=__RequestVerificationToken]').val());
        formData.append('file', $('[data-upload-contract-form]')[0]);
        if ($('[data-upload-file]').val() != "") {
            $.ajax({
                url: $(this).attr('action'),
                data: formData,
                type: 'POST',
                processData: false,
                contentType: false,
                success: function (data) {
                    if (data.Success === true) {
                        $('[data-contract-error-message]').text();
                        ReturnDataTableForUploadFile($('[data-upload-file-supplier-contract-id]').val());
                        table.ajax.reload();
                    }
                    else {
                        $('[data-contract-error-message]').show();
                        $('[data-contract-error-message]').text(data.ResponseText);
                    }
                }
            })
            .fail(function () {
                $('[data-contract-error-message]').show();
                $('[data-contract-error-message]').text("Something went wrong uploading your file, please try again.");
            });
        }
        else {
            $('[data-contract-error-message]').show();
            $('[data-contract-error-message]').text("No contract to upload");
        }
    });

My own function (using jQuery) which works fine: (it's not complete, but at least it reports back it received the file ;))

<script type="text/javascript">
    function uploadFileThroughForm(messageId) {
        var form = $('#addAttachmentForm');
        if (form.valid()) {
            var files = $('#filenameToUpload').prop('files');
            if (files.length > 0) {
                if (window.FormData !== undefined) {
                    var formData = new FormData();
                    formData.append("__RequestVerificationToken", $('#addAttachmentForm input[name=__RequestVerificationToken]').val());
                    formData.append("file", files[0]);
                    $.ajax({
                        type: "POST",
                        url: '@ApplicationAdapter.GetVirtualRoot()Attachment/Add/' + messageId,
                        contentType: false,
                        processData: false,
                        data: formData,
                        success: function(result) {
                            alert(result.responseMessage);
                        },
                        error: function(xhr) {
                            alert(xhr.responseText);
                        }
                    });
                } else {
                    alert("This browser doesn't support HTML5 file uploads!");
                }
            }
        }
    }
</script>

Hope this helps, even if it's been a while since you asked this question!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM