验证防伪密钥不适用于ajax post

mar*_*ibe 1 javascript c# model-view-controller asp.net-ajax asp.net-core

添加我尝试通过 ajax post 请求使用验证防伪令牌,但响应是找不到根元素。我删除了防伪令牌,它工作得很好。

这是我的代码:javascript;

  function Save() {
        let GroupName = GetElementValue("GroupName");
        let GroupId = GetElementValue("GroupId");
        var Group = {
            __RequestVerificationToken: gettoken(),
            GroupId: :1",
            GroupName: "My Group Name"
        };

        if (IsFormValid("GroupForm")) {
            AjaxPost("/Groups/AddGroup", Group).done(function () {
                GetGroups();
            });
        }
    }


     function gettoken() {
        var token = '@Html.AntiForgeryToken()';
        token = $(token).val();
        return token;
   }

function AjaxPost(url, data) {
    return $.ajax({
        type: "post",
        contentType: "application/json;charset=utf-8",
        dataType: "json",
        responseType: "json",
        url: url,
        data: JSON.stringify(data)
    });
}
Run Code Online (Sandbox Code Playgroud)

我也尝试过这个:

$.ajax({
    type: "POST",
    url: "/Groups/AddGroup",
    data: {
        __RequestVerificationToken: gettoken(),
        GroupId: 1,
        GroupName: "please work"
    },
    dataType: 'json',
    contentType: 'application/x-www-form-urlencoded; charset=utf-8',

});
Run Code Online (Sandbox Code Playgroud)

这是后端:

  [HttpPost]
        [ValidateAntiForgeryToken]
        public void AddGroup([FromBody] GroupView Group)
        {
            if (Group.GroupName.Trim().Length>0)
            {
                bool existed = _context.Groups.Any(x => x.GroupName.ToLower().TrimEnd().Equals(Group.GroupName.ToLower().TrimEnd()));
                if (!existed)
                {
                    Groups group = new Groups()
                    {
                        GroupName = Group.GroupName
                    };
                    _context.Groups.AddAsync(group);
                    _context.SaveChanges();
                    int? groupId = group.GroupId;
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

这里参数传递完美

这是我的班级 GroupView

public class GroupView
{
    public string GroupId { get; set; }
    public string GroupName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我想使用正常发送带有数据的串行令牌的方法,如何才能使其工作?任何帮助!

Ale*_*der 6

在 ASP.NET Core 中,您可以通过表单或标头传递防伪令牌。所以我可以为您推荐 2 个解决方案。

解决方案 1. 标头

为了让框架从标头读取令牌,您需要配置AntiforgeryOptions并设置HeaderName为非null值。将此代码添加到Startup.cs

//or if you omit this configuration 
//HeaderName will be "RequestVerificationToken" by default
services.AddAntiforgery(options =>
{
    options.HeaderName = "X-CSRF-TOKEN"; //may be any other valid header name
});
Run Code Online (Sandbox Code Playgroud)

并传入防伪令牌AJAX

function Save() {
    //..
    //no need to set token value in group object
    var Group = {
        GroupId: "1",
        GroupName: "My Group Name"
    };
    //..
}

function AjaxPost(url, data) {
    return $.ajax({
        type: "post",
        contentType: "application/json;charset=utf-8",
        dataType: "json",
        responseType: "json",
        headers: {
            "X-CSRF-TOKEN": gettoken()
        },
        url: url,
        data: JSON.stringify(data)
});
Run Code Online (Sandbox Code Playgroud)

解决方案2.表格

您已经尝试通过表单传递令牌,但没有成功。为什么?原因是IAntiforgeryTokenStore(用于从请求中读取令牌)的默认实现无法从 json 中读取防伪令牌,而是将其作为表单数据读取。如果您想让它工作,那么不要stringify请求数据并contentType从调用中删除属性$.ajax。JQuery 将为您分别设置适当的内容类型和序列化数据。

//all other original code is unchanged, group needs to contain a token
function AjaxPost(url, data) {
    return $.ajax({
        type: "post",
        dataType: "json",
        responseType: "json",
        url: url,
        data: data
});
Run Code Online (Sandbox Code Playgroud)

此外,在这种情况下,您还需要[FromBody]从操作参数中删除属性,以便让模型绑定器正确绑定模型

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddGroup(GroupView group)
Run Code Online (Sandbox Code Playgroud)