7

所以,我一直在用这个撞墙,我找不到任何好的来源。也许我忘记了模型绑定的东西在 MVC3 中是如何工作的,但这是我想要做的:我有一个与 Knockout 绑定的编辑器来处理模型的编辑。该模型没有太多内容:

public class SetupTemplate
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Template { get; set; }
} 

我试图调用的动作的签名是:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UpdateTemplate(SetupTemplate template)

从这里的另一个问题中,我选择了这个相当有用的片段来获取防伪令牌:

window.addAntiForgeryToken = function(data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
};

这一切都与我试图通过 ajax 发布更新一起出现:

payload = window.addAntiForgeryToken(ko.mapping.toJS(self.data));
$.ajax({
    type: "post",
    url: endpoint,
    data: payload,
    success: function(data) {
        //Handle success
    }});

这导致了 Chrome 开发者工具的表单数据部分

Id:1
Name:Greeting
Template: [Template Text]
__RequestVerificationToken: [The really long anti-forgery token]

防伪令牌被拾起,但我的模型为空。我见过的大多数例子只使用一个传递的参数,而不是模型。

我确定我错过了一些明显的东西,关于它可能是什么的任何见解?

编辑:响应@Mark,将调用更改为:

$.ajax({
type: "post",
dataType: "json",
contentType: 'application/json',
url: endpoint,
data: JSON.stringify(payload),
success: function(data) {
    //Do some stuff
}});

产生这样的请求有效负载:

{"Id":1,"Name":"Greeting","Template":"...","__RequestVerificationToken":"..."}:

并且服务器没有拿起防伪令牌。这在有和没有contentType参数的情况下都试过了$.ajax()

4

5 回答 5

2

映射不适用于作为模板的参数,因为它与具有相同名称(大小写)的属性之一发生冲突。如果您使用模板以外的任何东西,它将适用于该控制器参数。

有一个解释详细信息的链接,我现在无法轻松找到。

public class SetupTemplate
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Template { get; set; }
} 
于 2012-12-07T21:16:50.930 回答
2

这是我的解决方案。像这样定义一个 jQuery 函数:

(function ($) {
    $.getAntiForgeryToken = function () {
        return $('input[name="__RequestVerificationToken"]').val();
    };

    // (!) use ValidateJsonAntiForgeryToken attribute in your controller
    $.ajaxJsonAntiforgery = function (settings) {

        var headers = {};
        headers['__RequestVerificationToken'] = $.getAntiForgeryToken();

        settings.dataType = 'json';
        settings.contentType = 'application/json; charset=utf-8';
        settings.type = 'POST';
        settings.cache = false;
        settings.headers = headers;
        return $.ajax(settings);
    };
})(jQuery);

它只是将您的验证令牌放入标头。您还需要过滤器属性来检查您的防伪令牌。这里是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;

namespace MyProject.Web.Infrastructure.Filters
{

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

在您的控制器中,这真的很简单,只需用新属性(ValidateJsonAntiForgeryToken)标记它:

[Authorize, HttpPost, ValidateJsonAntiForgeryToken]
public ActionResult Index(MyViewModel viewModel)

在客户端:

$.ajaxJsonAntiforgery({
    data: dataToSave,
    success: function() { alert("success"); },
    error: function () { alert("error"); }
});

这个对我有用。享受!

于 2013-11-19T11:32:35.983 回答
1

你可以尝试使用JSON.stringify吗?

$.ajax({     
   type: "post",     
   url: endpoint,     
   data: JSON.stringify(payload),     
   success: function(data) {         
      //Handle success     
   } 
});
于 2012-08-30T11:32:05.277 回答
1

@Mark 因引导我走上正确的道路而受到赞誉,并为我指出了一些链接,这些链接现在让我可以相当透明地处理防伪令牌。但是,解决问题的方法正在发生变化:

public ActionResult UpdateTemplate(SetupTemplate template)

至:

public ActionResult UpdateTemplate(SetupTemplate model)

现在它正确地填充了值。我真的很想知道为什么会修复它,但现在,它有效。

于 2012-08-30T14:40:10.530 回答
0

实际上,以下内容对我来说是一个复杂的对象;

var application = {
    Criteria: {
        ReferenceNumber: $("input[name='Criteria.ReferenceNumber'").val()
    },
    AppliedVia: "Office"
};

// get the next step
$.ajax({
    url: form.attr("action"),
    dataType: "html",
    type: "POST",
    data: {
        __RequestVerificationToken: $("input[name=__RequestVerificationToken]").val(),
        application: application
    },
}

然而,需要注意的一件事是确保左侧应该是您的方法/操作中的实际参数名称applicationdata这适用于 MVC 5(.NET Core 之前)

于 2016-08-17T12:57:19.910 回答