【问题标题】:Append antiforgery token to XMLHttpRequest将防伪令牌附加到 XMLHttpRequest
【发布时间】:2019-01-31 23:34:46
【问题描述】:

和标题说的差不多。这是javascript ...在不验证令牌时可以正常工作。验证时似乎看不到它,因为我收到 The required anti-forgery form field "__RequestVerificationToken" is not present. 错误。

var downloadEmailSignature = function (control) {
    if (control) {
        let form = $(control).closest('form');
        let token = $(form).find('input[name="__RequestVerificationToken"]').val();

        if (form) {
            let request = new XMLHttpRequest();
            request.open("POST", "Forms/DownloadEmailSignature");
            request.responseType = "blob";
            request.setRequestHeader('RequestVerificationToken', token);
            request.data = form.serialize();
            request.onload = function () {
                if (window.clientData.browser.name === "Internet Explorer") {
                    window.navigator.msSaveBlob(this.response, "EmailSignature.hta");
                }
                else{
                    let url = window.URL.createObjectURL(this.response);
                    let a = document.createElement("a");
                    document.body.appendChild(a);
                    a.href = url;
                    a.download = this.response.name || "download-" + $.now();
                    a.click();
                }
            };
            console.dir(request);
            request.send();
        }
    }
};

以及背后的代码...

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult DownloadEmailSignature(string emailSignature)
    {
        var hta = (MediaItem)SitecoreContext.GetItem<Item>(new Guid("{EE806F14-5BD3-491C-9169-DA701357FB45}"));

        using (var reader = new StreamReader(MediaManager.GetMedia(hta).GetStream().Stream))
        {
            var htaText = reader.ReadToEnd();

            htaText = htaText.Replace("*CARDSTRING*", emailSignature);

            var stream = new MemoryStream(htaText.ToASCIIByteArray());

            return new FileStreamResult(stream, "application/hta");
        }
    }

最后是视图...

<form id="download-email-signature" method="POST" enctype="multipart/form-data">
    @Html.HiddenFor(m => m.EmailSignatureMarkup)
    @Html.AntiForgeryToken()                                          
    @Html.FormIdentifier("FormsController", "DownloadEmailSignature")
    <a href="#" id="download-installer" onclick="downloadEmailSignature(this); return false;" class="btn-primary" style="margin-bottom:10px;margin-top:-10px;text-align:center;">Download installer</a>
</form>

【问题讨论】:

  • 这:在不验证令牌时工作正常。 似乎表明令牌不存在或无效。您设置了自定义 HTTP 标头,但不显示它是如何使用的,甚至不显示它是如何使用的。您采取了哪些措施来确保它在两端都存在并且有效?标头是否包含令牌?
  • @RandyCasburn 它存在于标记中,我已将 token 记录到它显示的控制台。应该在问题中明确说明
  • 和标题?
  • @RandyCasburn 该标头存在于请求标头列表中。那不是问题。 [ValidateAntiForgeryToken] 注释服务器端应该查找此标头。不管什么原因,它都看不到它。它是 asp.net mvc 的开箱即用功能
  • 您的 downloadEmailSignature 函数适用于手工编码的 HTML。请提供显示在浏览器中的已解析 HTML 输出。附带说明一下,在 token= 赋值语句中,$() 周围不需要 form,因为它已经是一个 jQuery 对象。

标签: javascript ajax asp.net-mvc xmlhttprequest antiforgerytoken


【解决方案1】:

如果您可以将XMLHttpRequest 替换为$.ajax(因为您已经加载了JQuery),那么下面的部分应该可以工作。

let form = $(control).closest('form');
let token = $(form).find('input[name="__RequestVerificationToken"]').val();

$.ajax({
    url: '/Home/DownloadEmailSignature',
    type: 'POST',
    data: {
        __RequestVerificationToken: token,
        emailSignature: 'emailSignature value'
    },
    success: function (result) {
        alert(result);
        //your code ....
    }
});

【讨论】:

  • 不幸的是,我不能在这种情况下使用 $.ajax,因为它不支持 responseType:'blob'。我将修改 af 标记,并将其作为数据的一部分而不是它自己的标头传递,然后查看
  • 不工作,奇怪的是我可以看到&amp;__RequestVerificationToken=...并且请求中的令牌正在发送但服务器端不能。打算搁置这个,只设置一个更传统的下载方法
【解决方案2】:

根据这里的答案:

ValidateAntiForgeryToken purpose, explanation and example

MVC 的防伪支持将唯一值写入仅 HTTP cookie,然后将相同的值写入表单。当页面 已提交,如果 cookie 值与 表单值。

这意味着 cookie 必须返回到服务器。这应该可以正常工作,除非您使用的是 IE9(已知该问题会导致此问题)。

我建议您添加 request.withCredentials = true; 以消除任何奇怪的 COR 相关问题。

如果涉及代理,cookie 也可能在返回服务器的过程中被剥离。

【讨论】:

  • 为帮助欢呼,但没有喜悦。我只好把它当作使用 sitecore 开发的另一个怪癖。我过去使用过 ajax 并附加了 af 令牌,没有任何问题,而且我一生都看不出它为什么不起作用。
  • @SeanT - 真可惜。我会在此处留下这个答案,以防将来对其他人有所帮助。
猜你喜欢
  • 1970-01-01
  • 2015-01-11
  • 2019-03-05
  • 2018-01-16
  • 2013-11-27
  • 2015-05-11
  • 2012-01-22
相关资源
最近更新 更多