在从jTable到MVC5执行CRUD项目时如何通过Anti Forgery Token?

时间:2014-07-11 03:58:21

标签: asp.net-mvc antiforgerytoken

当从jTable到我的MVC5控制器进行CRUD调用时,如何传递AntiForgeryToken?为了完成动作,我必须注释掉看似相当不安全的ValidateAntiForgeryToken部分。如果没有,那么我得到“与服务器通信时出错”。消息。

jTable代码:

    $(document).ready(function () {

    //Prepare jtable plugin
    $('#CandidateTable').jtable({
        title: 'Candidates',
        actions: {
            listAction: '@Url.Action("List")',
            deleteAction: '@Url.Action("Delete")',
            updateAction: '@Url.Action("Edit")',
            createAction: '@Url.Action("Create")'
        },
        fields: {
            ID: {
                key: true,
                create: false,
                edit: false,
                list: false
            },
            FirstName: {
                title: '@Html.DisplayNameFor(model => model.FirstName)',
                width: '15%'
            },
            MiddleName: {
                title: '@Html.DisplayNameFor(model => model.MiddleName)',
                width: '15%'
            },
            LastName: {
                title: '@Html.DisplayNameFor(model => model.LastName)',
                width: '15%'
            },
            AnonymousID: {
                title: '@Html.DisplayNameFor(model => model.AnonymousID)',
                width: '15%'
            },
            Email: {
                title: '@Html.DisplayNameFor(model => model.Email)',
                width: '15%'
            },
            GUID: {
                title: '@Html.DisplayNameFor(model => model.GUID)',
                width: '15%',
                create: false,
                edit: false
            }
        }
    });

    //Load person list from server
    $('#CandidateTable').jtable('load');
});

ASP.NET MVC 5创建操作:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public JsonResult Create([Bind(Include = "FirstName,MiddleName,LastName,AnonymousID,Email")] Candidate candidate)
    {
        try
        {
            if (ModelState.IsValid)
            {
                candidate.GUID = System.Guid.NewGuid();
                candidate.IsActive = true;
                candidate.DateAdded = DateTime.Now.ToUniversalTime();
                candidate.DateModified = null;
                db.Candidates.Add(candidate);
                db.SaveChanges();

                return Json(new { Result = "OK", Record = candidate });
            }
            else
            {
                throw new Exception("Form is not valid! Please correct it and try again.");
            }                
        }
        catch (Exception ex)
        {                
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
            return Json(new { Result = "ERROR", Message = ex.Message });
        }            
    }

更新:

我明白了。我需要添加一个任意字段( AFT ),然后添加@ HTML.AntiForgeryToken输出的自定义输入。现在我只需要弄清楚如何在Deletes上执行此操作,因为Delete只传递主键(id)

  $('#CandidateTable').jtable({
        paging: true,
        pageSize: 15,
        sorting: true,
        defaultSorting: 'LastName ASC',
        title: 'Candidates',
        actions: {
            listAction: '@Url.Action("List")',
            deleteAction: '@Url.Action("Delete")',
            updateAction: '@Url.Action("Edit")',
            createAction: '@Url.Action("Create")'
        },
        fields: {
            ID: {
                key: true,
                create: false,
                edit: false,
                list: false
            },
            FirstName: {
                title: '@Html.DisplayNameFor(model => model.FirstName)',
                width: '15%'
            },
            MiddleName: {
                title: '@Html.DisplayNameFor(model => model.MiddleName)',
                width: '15%'
            },
            LastName: {
                title: '@Html.DisplayNameFor(model => model.LastName)',
                width: '15%'
            },
            AnonymousID: {
                title: '@Html.DisplayNameFor(model => model.AnonymousID)',
                width: '15%'
            },
            Email: {
                title: '@Html.DisplayNameFor(model => model.Email)',
                width: '15%'
            },                
            __AFT__: {
                create: true,
                edit: true,
                list: false,
                input: function (data) {
                    return '@Html.AntiForgeryToken()';
                }
            }

        }

3 个答案:

答案 0 :(得分:1)

我已经找到了如何添加这个AntiForgeryToken来删除jTable的动作。您已正确添加__AFT__到创建和更新操作,无需在控制器中添加标头和提取。要将其添加到删除操作,您可以编写自定义删除,如下所示。更新了您的代码

var tokenId = '@Html.AntiForgeryToken()';

$('#CandidateTable').jtable({
    paging: true,
    pageSize: 15,
    sorting: true,
    defaultSorting: 'LastName ASC',
    title: 'Candidates',
    actions: {
        listAction: '@Url.Action("List")',
        deleteAction: function (postData) {
            postData.__RequestVerificationToken = $(tokenId).val();
            return $.Deferred(function ($dfd) {
                $.ajax({
                    url: '@Url.Action("Delete")',
                    type: 'POST',
                    dataType: 'json',
                    data: postData,
                    success: function (data) {
                        $dfd.resolve(data);
                    },
                    error: function () {
                        $dfd.reject();
                    }
                });
            });
        },
        updateAction: '@Url.Action("Edit")',
        createAction: '@Url.Action("Create")'
    },
    fields: {
        ID: {
            key: true,
            create: false,
            edit: false,
            list: false
        },
        FirstName: {
            title: '@Html.DisplayNameFor(model => model.FirstName)',
            width: '15%'
        },
        MiddleName: {
            title: '@Html.DisplayNameFor(model => model.MiddleName)',
            width: '15%'
        },
        LastName: {
            title: '@Html.DisplayNameFor(model => model.LastName)',
            width: '15%'
        },
        AnonymousID: {
            title: '@Html.DisplayNameFor(model => model.AnonymousID)',
            width: '15%'
        },
        Email: {
            title: '@Html.DisplayNameFor(model => model.Email)',
            width: '15%'
        },                
        __AFT__: {
            create: true,
            edit: true,
            list: false,
            input: function (data) {
                return tokenId;
            }
        }

    }

我自己测试并尝试过这个。希望这会有所帮助。

答案 1 :(得分:0)

要做的第一件事是向View添加一个会生成防伪令牌的函数:

@functions{
    public string TokenHeaderValue()
    {
        string cookieToken, formToken;
        AntiForgery.GetTokens(null, out cookieToken, out formToken);
        return cookieToken + ":" + formToken;                
    }
}

@functions块允许您向Views添加功能。它们有助于将所有功能保存在一个有助于组织的位置。

然后,在您的Javascript中,您将进行AJAX调用并将该标记添加为RequestVerificationToken标题:

$.ajax("api/values", {
    type: "post",
    contentType: "application/json",
    data: {  }, // JSON data goes here
    dataType: "json",
    headers: {
        'RequestVerificationToken': '@TokenHeaderValue()' //Can be named whatever
    }
});

现在在解决方案中创建以下实用程序方法:

void ValidateRequestHeader(HttpRequestMessage request)
{
    string cookieToken = "";
    string formToken = "";

    IEnumerable<string> tokenHeaders;
    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
    {
        string[] tokens = tokenHeaders.First().Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}

并称之为:

try{
   Utils.ValidateRequestHeader(request);
}
catch(HttpAntiForgeryException exc){
   //VALIDATION FAILED! RELEASE THE HOUNDS
}

参考:http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-(csrf)-attacks

答案 2 :(得分:0)

我有这个代码,也许它会帮助你。我猜jtable使用$ .ajax来处理它的请求,所以我想它应该可以工作。

// Setup CSRF safety for AJAX:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").eq(0);
        var headers = {};
        headers["__RequestVerificationToken"] = token.val();
        if (!token.length) return;

        var tokenName = token.attr("name");

        // If the data is JSON, then we need to put the token in the QueryString:
        if (options.contentType.indexOf('application/json') === 0) {
           // Add the token to the URL, because we can't add it to the JSON data:
           options.headers = headers;
        } 
   }
});