问题
I am having problems getting Microsoft's MVC's [ValidateAntiForgeryToken]
to work with a Single Page Application (SPA) written using Marionette & Backbone. The problem seems to be that the MVC [ValidateAntiForgeryToken]
method fails to see the token we send as part of the JSON. We thought it was because the token had to be in the Forms part of the reply but MrOggy85 says that isn't a problem (see his answer below).
The code is in my api controllers, which use AttributeRouting, which we assume is causing the problem. A typical action looks like this:
// POST api/vizschemes/
[POST("")]
[Authorize(Roles = "...some role...")]
[ValidateAntiForgeryToken]
public ActionResult Add(CreateUpdateSmVizSchemeDto dto, ICreateSmVizScheme service)
{
... code to update the VizScheme and return json
}
Has anyone else overcome this? A lot of googling turned up the comment in is post "ASP.NET MVC provides built-in support for anti-forgery tokens, through the AntiForgery class and the [ValidateAntiForgeryToken] attribute. Currently, this functionality is not built into Web API. However, the (KnockoutJS) template includes a custom implementation for Web API.". This suggests that they write their own, which I can do.
Has anyone else hit this, and if so how did you solve it? Am I missing something obvious or should I just write my own ValidateAntiForgeryToken method? Your input would be appreciated.
UPDATE
GREAT stackoverflow link provided by @MrOggy85 with lots more information in it. See How can i supply an AntiForgeryToken when posting JSON data using $.ajax? . I plan to write my own AntiForgery test and will post when I have done.
回答1:
When you use the helper @Html.AntiForgeryToken()
in a view this is the actual HTML result:
<input name="__RequestVerificationToken" type="hidden"
value="{ long cryptic code }">
This input field is normally inside your <form>
-element which means it will be attached to the request if you submit that form.
The problem occurs when this input field is outside of your form or if you are not submitting a form. Have no fear, there is a solution for this. The attribute [ValidateAntiForgeryToken]
tells the server to look for a key with the name: "__RequestVerificationToken". Let's give the server what it wants!
First, get that value!
var antiforgeytoken = $('input[name=__RequestVerificationToken]').val();
Second, attach it to your AJAX-request (I use jQuery)
$.ajax({
url: 'something/something',
type: 'POST',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8', // Default
data: { 'somekey': 'someval',
'__RequestVerificationToken', antiforgeytoken }
});
Now your server is happy, and you are too!
Update:
The content type is important because of how the MVC Binder validates the request. If you want to use another content type this solution How can i supply an AntiForgeryToken when posting JSON data using $.ajax? proposes to separate the antiforgery token and the postdata in two different parameters.
回答2:
I don't know about AntiForgery, but Backbone can be configured to emulate REST and emulate JSON to circumvent this kind of limitation from the server.
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;
This will tell Backbone to use only POST
method for delete()
and update()
and send the data as application/x-www-form-urlencoded
instead of application/json
.
来源:https://stackoverflow.com/questions/17898625/how-to-test-antiforgerytoken-in-mvc4-with-backbone-single-page-application