8

I implemented the Razor equivalent for the solution described in the accepted answer for this Question: jQuery Ajax calls and the Html.AntiForgeryToken() But I kept getting the following exception:

System.Web.Mvc.HttpAntiForgeryException (0x80004005): The required anti-forgery form field "__RequestVerificationToken" is not present.

edit

I manged to workaround it doing this:

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

function CallAjax(url, type, data, success, error) {

    var ajaxOptions = { url: url, type: type, contentType: 'application/json'};

    if (type == 'POST') {
        var fd = new window.FormData();
        fd = AddAntiForgeryToken(fd);
        $.each(data, function (i, n) {
            fd.append(i,n);
        });
        data = fd;
        ajaxOptions.processData = false;
        ajaxOptions.contentType = false;
    }

    ajaxOptions.data = data;

    if (success) ajaxOptions.success = success;

    //If there is a custom error handler nullify the general statusCode setting.
    if (error) {
        ajaxOptions.error = error;
        ajaxOptions.statusCode = null;
    };

    $.ajax(ajaxOptions);
}

But unfortunately FormData() is only supported in latest browser versions. Any workaround that could work before FormData() as introduced?

edit I wonder why the ValidateAntiForgeryTokenAttribute looks for the AntyForgeryToken only in the Form data, and doesn't look for it in the rout values as you can see below in the code of the sealed classes AntiForgeryTokenStore and AntiForgeryWorker?

public void Validate(HttpContextBase httpContext)
{
  this.CheckSSLConfig(httpContext);
  AntiForgeryToken cookieToken = this._tokenStore.GetCookieToken(httpContext);
  AntiForgeryToken formToken = this._tokenStore.GetFormToken(httpContext);
  this._validator.ValidateTokens(httpContext, AntiForgeryWorker.ExtractIdentity(httpContext), cookieToken, formToken);
}


public AntiForgeryToken GetFormToken(HttpContextBase httpContext)
{
  string serializedToken = httpContext.Request.Form[this._config.FormFieldName];
  if (string.IsNullOrEmpty(serializedToken))
    return (AntiForgeryToken) null;
  else
    return this._serializer.Deserialize(serializedToken);
}
Community
  • 1
  • 1
RonyK
  • 2,644
  • 5
  • 32
  • 42

3 Answers3

5

Well, after digging some more I found a nice solution to my problem in this link: ASP.NET MVC Ajax CSRF Protection With jQuery 1.5

As far as I understand the solution described in the chosen answer for this question: jQuery Ajax calls and the Html.AntiForgeryToken(), shouldn't work (indeed it failed for me).

Community
  • 1
  • 1
RonyK
  • 2,644
  • 5
  • 32
  • 42
1

Create antiforgerytoken:

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    <input ...>
}

Create a function to add the token to the ajax request :

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

You can then use it like this:

$.ajax({
   type: "POST",
   url: '@Url.Action("MyMethod", "MyController", new {area = "MyArea"})',
   dataType: "json",
   traditional: true,
   data: addRequestVerificationToken( { "id": "12345678" } );
})
.done(function(result) {
   if (result) {
       // Do something
   } else {
       // Log or show an error message
   }
   return false;
});
Krishna
  • 5,194
  • 2
  • 28
  • 33
  • Any idea how can we handle for JQuery MVC postback https://forums.asp.net/t/2104049.aspx?Grid+Inline+Editing+JQuery+PostBack – singhswat Sep 20 '16 at 16:29
  • 1
    STEP 1. Use @Html.AntiForgeryToken() in you view, HTML. STEP 2. Add _RequestVerificationToken=$('input[name=__RequestVerificationToken]').val() in the data you are sending. – Krishna Sep 22 '16 at 07:42
0

When you call CallAjax(), where is data coming from? I ask because, usually when your data comes from a form then your CSRF token is already part of the form, typically in a hidden field.

<form action="yourPage.html" method="POST">
    <input type="hidden" name="__RequestVerificationToken" value="......"/>
    .... other form fields ....
</form>

So if your data is all coming from a form, then you should just make sure that the token is a hidden part of that form and the token should automatically be included.

If your data is coming from somewhere other than a form, then it is understandable that you would stash your token somewhere and then include it after the data has been assembled. But you might consider adding the token to the data, rather than building a new object from the token and then adding all the data to it.

if (type == 'POST') {
    data._RequestVerificationToken = $("input[name='__RequestVerificationToken']").val();
    ajaxOptions.processData = false;
    ajaxOptions.contentType = false;
}
Winner Crespo
  • 1,644
  • 15
  • 29
slashingweapon
  • 11,007
  • 4
  • 31
  • 50
  • As described in the Q/A I linked to, the data is a json object built by client business logic implemented using jQuery, It is not part of any form. I can build the data the way you described, but the problem remains as I still need the data to be passed as FormData() – RonyK May 29 '13 at 06:06