Javascript 如何在没有表单的情况下将AntiForgery令牌传递给控制器

Javascript 如何在没有表单的情况下将AntiForgery令牌传递给控制器,javascript,jquery,asp.net,asp.net-core,Javascript,Jquery,Asp.net,Asp.net Core,我有这个jquery函数,我想向控制器传递一个antiforgery令牌以进行验证。然而,我当前的方法是返回一个错误400,不管我是通过标题还是通过正文传递它 我把这张空表格放在我的页面顶部 @using (Html.BeginForm(null, null, FormMethod.Post, new { id = "form" })) { @Html.AntiForgeryToken() } 这是jquery函数。我在标题和正文中有requestverificationtoken,但

我有这个jquery函数,我想向控制器传递一个antiforgery令牌以进行验证。然而,我当前的方法是返回一个错误400,不管我是通过标题还是通过正文传递它

我把这张空表格放在我的页面顶部

@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "form" }))
{
    @Html.AntiForgeryToken()
}
这是jquery函数。我在标题和正文中有requestverificationtoken,但它不起作用

$("#eventGenerateButton").on("click", function (e) {
    e.preventDefault();
    var event_form_data = {
        "__RequestVerificationToken": token,
        "StartDate": $("#eventStartDate").val(),
        "EndDate": $("#eventEndDate").val(),
    };

    $.ajax({
        url: "@Url.Action("GenerateEventLogsReport", @ViewContext.RouteData.Values["controller"].ToString())",
        method: "POST",
        headers: { "__RequestVerificationToken": token},
        xhrFields: {
            responseType: 'blob'
        },
        data: JSON.stringify(event_form_data),
        contentType: "application/json",
        success: function (result) {
            GenerateReport(result,"EventLogs");
        },
        error: function (error) {
            console.log(error);
        }
    });
    return false;
});
这是控制器

[HttpPost]
[ValidateAntiForgeryToken]
public FileResult GenerateEventLogsReport([FromBody]GenericReportDateViewModel Input)
{

}

尝试将控制器签名更改为:

public FileResult GenerateEventLogsReport(string __RequestVerificationToken, string StartDate, string EndDate)
{

}

事件表单数据中删除令牌,然后尝试发送请求头,如

var event_form_data = {
    "StartDate": $("#eventStartDate").val(),
    "EndDate": $("#eventEndDate").val(),
    };
var token = $('input[name="__RequestVerificationToken"]').val();
$.ajax({
    url: "/Home/AjaxPost",
    method: "POST",      
    headers: { "RequestVerificationToken": token},
    xhrFields: {
        responseType: 'blob'
    },
    data: JSON.stringify(event_form_data),
    contentType: "application/json",
    success: function (result) {

    },
    error: function (error) {
        console.log(error);
    }
});
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple=false,Inherited=true)]
///此属性用于验证antiforgery,无论它是如何发送的。
///它不在乎标记是在头中还是在正文中,正文可以字符串化。
公共密封类MyValidateAntiForgeryAttribute:FilterAttribute,IAAuthorizationFilter
{
授权时的公共无效(AuthorizationContext filterContext)
{
如果(filterContext==null)
{
抛出新ArgumentNullException(“filterContext”);
}
var httpContext=filterContext.httpContext;
/*注意:防伪标识从一个页面传递两次,从一个页面传递一次
*帖子本身,并一度作为cookie进行验证
*值不匹配。它们是一个整体的两部分,并且都得到
*传递到验证例程中*/
var cookie=httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
//先试试页眉
var-token=httpContext.Request.Headers[“uu-RequestVerificationToken”];
//尝试正常方法
if(标记==null)
{
for(int cl=0;cl
在以下情况下,您无法使用股票验证器验证防伪令牌:

  • json被序列化
  • 你在标题中传递它
  • 您可以在url中传递它
  • 如果您需要执行上述任何操作,您需要编写自己的反伪造检查,以便在传递的数据中找到令牌。 我已经写了一份防伪检查,检查内容如下:

  • 检查url中的令牌
  • 在序列化数据中检查它
  • 在标题中检查它。 请随意使用它。请注意,这(故意)并不是筛选出GET。如果您在类级别添加它,您可能需要添加它

  • 嗯?它甚至不会命中控制器签名,因为它未能通过[ValidateAntiForgeryToken]部分。如何获取
    令牌
    ?并确保数据正确。var token=$('input[name=“\uu RequestVerificationToken”]”)。val();这就是我得到它的方式。很抱歉迟到了。它在我的本地运行得很好。。你能分享一个可复制的演示吗?这甚至有效吗?控制器中的反伪造检查默认情况下会忽略标题,并且正在寻找一个以_uu开头的密钥
    {
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
                AllowMultiple = false, Inherited = true)]
    ///this attribute is for validating antiforgery, no matter how it's sent.
    ///It doesn't care if the token is in the header or body, and the body can be stringified.
    public sealed class MyValidateAntiForgeryAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            
            var httpContext = filterContext.HttpContext;
            
                /* Note:  Antiforgery tokens are passed twice from a page.  Once from
                 * the post itself, and once as a cookie to verify against it.  The
                 * values do not match.  They are two halves of a whole and both get
                 * passed into the validation routine. */
                var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
                //try header first
                var token = httpContext.Request.Headers["__RequestVerificationToken"];
                //try normal method
                if (token == null)
                {
                    for (int cl = 0; cl < httpContext.Request.Form.Keys.Count; cl++)
                    {
                        if (httpContext.Request.Form.Keys[cl] == "__RequestVerificationToken")
                        {
                            token = httpContext.Request.Form[httpContext.Request.Form.Keys[cl]];
                        }
                    }
                }
                //try url
                if (token == null)
                {
                    for (int cl = 0; cl < httpContext.Request.QueryString.Keys.Count; cl++)
                    {
                        if (httpContext.Request.QueryString.Keys[cl] == "__RequestVerificationToken")
                        {
                            token = httpContext.Request.QueryString[httpContext.Request.QueryString.Keys[cl]];
                        }
                    }
                }
                /* if still null, check to see if it's in a json string.
                   this section will retrieve the token out of a serialized dataset.
                */
                if (token == null)
                {
                    string json;
                    var position = httpContext.Request.InputStream.Position;
                    using (var reader = new StreamReader(httpContext.Request.InputStream, Encoding.UTF8, false, 8192, true))
                    {
                        json = reader.ReadToEnd();
                        //you MUST reset the input stream to start or you will break post.
                        httpContext.Request.InputStream.Seek(position, SeekOrigin.Begin);
                        try
                        {
                            var jsonObj = Json.Decode(json); //attempt to parse into json object.  
                            token = jsonObj["__RequestVerificationToken"];
                        }
                        catch
                        {
                            //eat the parse errors.  That simply means it's not json.
                        }
                    }
                }
                AntiForgery.Validate(cookie?.Value, token);
            
        }
    }