如何使用自定义“__RequestVerificationToken”?

时间:2017-05-17 19:56:13

标签: asp.net-mvc asp.net-core

我已经制作了这样的局部视图(位置:MyController/_Form.cshtml):

<form asp-antiforgery="true">
    <input type="button" value="submit" />
</form>

Controller中的一些操作:

[HttpPost, ValidateAntiForgeryToken]
public IActionResult Test()
{
    return Ok(new { succeeded = true });
}

[HttpPost]
public IActionResult GetTemplate()
{
    string template = _viewRender<string>("MyController/_Form", null);
    return Ok({ template = template });
}

_viewRender是一项将部分视图转换为字符串的服务。

我已经测试了这些步骤:

使用jquery从客户端向服务器发出请求以获取模板并附加到某个div。

let onSuccess = function (data) {
    $(data.template).appendTo('.myDiv');
};

$.ajax({
    url: '/MyController/GetTemplate',
    method: 'POST'
}).done(onSuccess).fail(onError);

检测提交表单的事件如下:

$(document).on('click', 'input[type=text]', function () {
    let _this = $(this);

    let token = _this.parent().find('[name=__RequestVerificationToken]').val();

    let onSuccess = function (data) {
        console.log(data); // should be: Object:{succeeded:true}
    };

    $.ajax({
        url: '/MyController/Test',
        method: 'POST',
        data: { __RequestVerificationToken: token },
        processData: false,
        contentType: false
    }).done(onSuccess).fail(onError);
});

当我提出请求时,我总是在404 - not found标签上收到错误代码Console

我确信路径是正确的。因此,我尝试从ValidateAntiForgeryToken操作中移除Test属性,然后再次尝试。它工作正常(请求状态代码200)。

所以,我猜这个问题(给出了404错误)来自令牌。我已经使用开发人员工具再次检查,我确信我有一个令牌。但我不知道如何检查令牌是否有效。

令牌是从服务器生成的。我刚刚提出要求并将其附加到身体上。然后,将其重新发送到服务器。但服务器不接受它。

为什么?

2 个答案:

答案 0 :(得分:2)

这就是在ASP.NET Core中完成的......

Input observable: >--a--b--c--d--| Signal observable: >------1---1-1-| Count in buffer: !--1--21-2-121-| Output observable: >------a---b-c-| 中,您需要设置防伪标题名称。

if(File.Exists("myLibrary.dll")
{
   MyForm frm = new MyForm();
   frm.ShowDialog();
}

您需要这样做,因为默认情况下,防伪只会考虑表单数据,我们希望它也能与ajax一起使用。

在您的Startup.cs文件中,您需要添加services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); ,这将使用验证令牌呈现隐藏的输入。

最后在您的ajax代码中,您需要在发送之前设置请求标头。

.cshtml

因此,在您的情况下,ajax代码将如下所示。

@Html.AntiForgeryToken()

答案 1 :(得分:0)

两件事。

首先,我使用自定义过滤器而不是ValidateAntiForgeryToken。我不记得为什么。可能ValidateAntiForgeryToken不能处理AJAX请求。

这是我使用的自定义过滤器的代码。

    [AttributeUsage(AttributeTargets.Class)]
public sealed class ValidateAntiForgeryTokenOnAllPostsAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException(nameof(filterContext));
        }
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie?.Value;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
            }
        }
    }
}

其次,令牌进入请求头而不是数据部分。我使用布局文件中的ajaxSetup将其添加到标头中。这样我就不用担心记得将它添加到每个AJAX请求中。

    $.ajaxSetup({
        cache: false,
        headers: { "__RequestVerificationToken": token }
    });