ajax 调用中不存在所需的防伪表单字段“__RequestVerificationToken”

Posted

技术标签:

【中文标题】ajax 调用中不存在所需的防伪表单字段“__RequestVerificationToken”【英文标题】:The required anti-forgery form field “__RequestVerificationToken” is not present in ajax call 【发布时间】:2018-01-28 03:26:37 【问题描述】:

我在控制器中有以下方法

[HttpPost]
[Authorize(Roles ="Klient")]
[ValidateAntiForgeryToken]
public ActionResult GetAvaiableHouses(DateTime startDate, DateTime endDate)

    Session.Remove("Reservation");
    IEnumerable <SelectListItem> avaiableHouses = repository.GetAllNamesAvaiableHouses(repository.GetAvaiableHousesInTerm(startDate, endDate));

    List<string> houses = new List<string>();
    avaiableHouses.ToList().ForEach(item => houses.Add(item.Value));

    if(avaiableHouses.ToList().Count == 0)
    
        return new EmptyResult();
    

    Session["Reservation"] = new NewReservation()
    
        StartDate = startDate,
        EndDate = endDate,
        AvaiableHouses = avaiableHouses
    ;

    return PartialView("~/Views/Shared/_AvaiableHousesPartial.cshtml", houses);

在View.cshtml中使用ajax脚本调用该方法

$(function () 
    $("#btnCheckAvaiableHouses").click(function () 

        $.ajax(
            type: "POST",
            url: "/ClientReservations/GetAvaiableHouses",
            data: 'startDate: "' + $("#startdate").val() + '",endDate:"' + $("#enddate").val() + '",__RequestVerificationToken:"' + $('input[name=__RequestVerificationToken]').val() +'"  ',
            contentType: "application/json; charset=utf-8",
            dataType: "text",
            success: function (response) 
                $('#avaiableHouses').html(response)
                if (!$('#avaiableHouses').is(':empty')) 
                    document.getElementById("btnConfirmTerm").style.visibility = 'visible';
                
                else 
                    $('#avaiableHouses').html('Brak dostępnych domków w podanym terminie')
                
            ,
            failure: function (response) 
                alert(response.responseText);
            ,
            error: function (response) 
                alert(response.responseText);
            
        );
    );
);

这是调用此脚本的按钮部分

<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="button" id="btnCheckAvaiableHouses" value="Sprawdź dostępność domków" class="btn btn-default" /> 
        <input type="button" id="btnConfirmTerm" value="Potwierdź termin" onclick="location.href='@Url.Action("Create", "ClientReservations")'"  class="btn btn-default" style="visibility:hidden" />
    </div>
</div>

我已经添加了附加参数

'",__RequestVerificationToken:"' + $('input[name=__RequestVerificationToken]').val() 

进入 ajax 脚本,但在执行过程中我仍然收到错误

,__RequestVerificationToken 不存在。

可能是什么原因?

【问题讨论】:

【参考方案1】:

如果您对数据进行字符串化并使用contentType: 'application/json,则将令牌添加到 ajax 标头中,例如

var headers =  __RequestVerificationToken: $('input[name="__RequestVerificationToken"]').val() ;

$.ajax(
    headers: headers,
    data: ... // remove the token from your existing implementation
    ....
);

然后您需要创建一个自定义 FilterAttribute 以从标头中读取值

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class ValidateHeaderAntiForgeryTokenAttribute : 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"]);
    

在您的控制器方法中,将[ValidateAntiForgeryToken] 替换为[ValidateHeaderAntiForgeryToken]

但是,没有必要对数据进行字符串化,可以使用

var data = 
    startDate: $("#startdate").val(),
    endDate: $("#enddate").val(),
    __RequestVerificationToken: $('input[name=__RequestVerificationToken]').val()
;

$.ajax(
    data: data,
    ....
);

并删除contentType 选项,使其使用默认的'application/x-www-form-urlencoded; charset=UTF-8'

您还没有显示您的表单,假设它包含@Html.AntiForgeryToken()@Html.TextBoxFor(m =&gt; m.startDate)@Html.TextBoxFor(m =&gt; m.endDate),您使用name="startDate"name="endDate" 生成表单控件,那么您可以简单地使用

var data = $('form').serialize();

$.ajax(
    data: data,
    ....
);

序列化所有表单控件,包括令牌

【讨论】:

以上是关于ajax 调用中不存在所需的防伪表单字段“__RequestVerificationToken”的主要内容,如果未能解决你的问题,请参考以下文章

从 ajax 方法调用操作引发错误:所需的防伪表单字段“__RequestVerificationToken”不存在

所需的防伪表单字段“__RequestVerificationToken”不存在 用户注册错误

所需的防伪表单字段“__RequestVerificationToken”不存在

jmeter中的相关问题:所需的防伪形式字段“__RequestVerificationToken”不存在

所需的防伪 cookie“__RequestVerificationToken”不存在

使用 jQuery Ajax 和 Html.AntiForgeryToken() 时,防伪表单字段“__RequestVerificationToken”不存在