使用防伪令牌将 JSON 模型发布到 ASP.Net MVC3
Posted
技术标签:
【中文标题】使用防伪令牌将 JSON 模型发布到 ASP.Net MVC3【英文标题】:Posting a JSON model to ASP.Net MVC3 with Anti-forgery token 【发布时间】:2012-08-24 19:05:01 【问题描述】:所以,我一直在用这个撞墙,我找不到任何好的来源。也许我忘记了模型绑定的东西在 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)
从这里的另一个问题中,我选择了这个相当有用的 sn-p 来获取防伪令牌:
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()
的情况下都进行了尝试。
【问题讨论】:
【参考方案1】:映射不适用于作为模板的参数,因为它与具有相同名称(大小写)的属性之一发生冲突。如果您使用除模板之外的任何其他内容,则该控制器参数将很好地工作。
有一个so链接解释了细节,我现在找不到了。
public class SetupTemplate
public int Id get; set;
public string Name get; set;
public string Template get; set;
【讨论】:
【参考方案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");
);
它对我有用。享受吧!
【讨论】:
这就像一个冠军@roman-pushkin。感谢您发布您的解决方案。 一段时间后,我发现“__RequestVerificationToken”不是一个好名字。最好选择“X-RequestVerificationToken”,这样代理服务器就会让这个标头通过。【参考方案3】:你可以试试JSON.stringify
吗?
$.ajax(
type: "post",
url: endpoint,
data: JSON.stringify(payload),
success: function(data)
//Handle success
);
【讨论】:
我更新了我的问题并对此做出了回应。简而言之:仍然没有骰子。 这篇文章haacked.com/archive/2011/10/10/preventing-csrf-with-ajax.aspx对你有帮助吗? 还有这个***.com/questions/2906754/… 感谢链接'Preventing CSRF With Ajax' - Phil Haack 已经为 MVC3/4 解决了这个问题。【参考方案4】:@Mark 因引导我走上正确的道路而受到赞誉,并为我指出了一些现在让我可以相当透明地处理防伪令牌的链接。但是,解决问题的方法正在发生变化:
public ActionResult UpdateTemplate(SetupTemplate template)
到:
public ActionResult UpdateTemplate(SetupTemplate model)
现在它正确地填充了值。我真的很想知道为什么会修复它,但现在它可以工作了。
【讨论】:
【参考方案5】:实际上,以下内容对我来说适用于复杂的对象;
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
,
但需要注意的一点是确保data
中的左侧application
应该是您的方法/操作中的实际参数名称。这适用于 MVC 5(.NET Core 之前)
【讨论】:
以上是关于使用防伪令牌将 JSON 模型发布到 ASP.Net MVC3的主要内容,如果未能解决你的问题,请参考以下文章
如果我在一个页面中添加多个表单,是不是需要在每个表单中添加单独的防伪令牌?
显然是随机错误:“防伪令牌验证失败。防伪 cookie 令牌和请求令牌不匹配。”