如何使用骨干单页应用程序在MVC4中测试AntiForgeryToken

时间:2013-07-27 14:00:58

标签: .net asp.net-mvc-4 backbone.js single-page-application attributerouting

我遇到问题,微软的MVC [ValidateAntiForgeryToken]使用Marionette& amp;写的单页应用程序(SPA)。骨干。问题似乎是MVC [ValidateAntiForgeryToken]方法无法看到我们作为JSON的一部分发送的令牌。我们认为这是因为令牌必须在回复的表格部分,但MrOggy85说这不是问题(见下面的回答)。

代码在我的api控制器中,使用AttributeRouting,我们认为这会导致问题。典型的操作如下所示:

    // POST api/vizschemes/
    [POST("")]
    [Authorize(Roles = "...some role...")]
    [ValidateAntiForgeryToken]
    public ActionResult Add(CreateUpdateSmVizSchemeDto dto,  ICreateSmVizScheme service)
    {
       ... code to update the VizScheme and return json
    }

还有其他人克服了这个吗?很多谷歌搜索出现的评论是post ASP.NET MVC通过AntiForgery类和[ValidateAntiForgeryToken]属性为反伪造令牌提供内置支持。目前,此功能是没有内置到Web API中。但是,(KnockoutJS)模板包含Web API的自定义实现。“。这表明他们自己编写,我可以做。

有没有人打过这个,如果有的话你是怎么解决的?我错过了一些明显的东西,还是应该编写自己的ValidateAntiForgeryToken方法?您的意见将不胜感激。

更新

由@ MrOggy85提供的GREAT stackoverflow链接,其中包含更多信息。见How can i supply an AntiForgeryToken when posting JSON data using $.ajax?。我计划编写自己的AntiForgery测试,并在完成后发布。

2 个答案:

答案 0 :(得分:2)

在视图中使用帮助器@Html.AntiForgeryToken()时,这是实际的HTML结果:

<input name="__RequestVerificationToken" type="hidden" 
value="{ long cryptic code }">

此输入字段通常位于<form> - 元素内,这意味着如果您提交该表单,它将附加到请求中。

如果此输入字段位于表单之外或者您未提交表单,则会出现此问题。不用担心,有一个解决方案。属性[ValidateAntiForgeryToken]告诉服务器查找名称为“__RequestVerificationToken”的密钥。让我们给服务器它想要的东西!

首先,获得该值!

var antiforgeytoken = $('input[name=__RequestVerificationToken]').val();

其次,将其附加到您的AJAX请求(我使用jQuery)

$.ajax({
  url: 'something/something',
  type: 'POST',
  contentType: 'application/x-www-form-urlencoded; charset=UTF-8', // Default
  data: { 'somekey': 'someval', 
          '__RequestVerificationToken', antiforgeytoken }
});

现在你的服务器很开心,你也是!

<强>更新
内容类型很重要,因为MVC Binder如何验证请求。如果您想使用其他内容类型,此解决方案How can i supply an AntiForgeryToken when posting JSON data using $.ajax?建议将防伪令牌和postdata分成两个不同的参数。

答案 1 :(得分:0)

我不知道AntiForgery,但Backbone可以配置为emulate RESTemulate JSON来规避服务器的这种限制。

Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;

这会告诉Backbone仅对POSTdelete()使用update()方法,并将数据发送为application/x-www-form-urlencoded而不是application/json