Search code examples
jsonajaxasp.net-mvc-4controllerantiforgerytoken

AJAX AntiForgery Token not calling controller method


I am struggling to call my controller method with [ValidateAntiForgeryToken] attribute.

My cshtml/js code :

    var wizardRegisterJsonRequest = {
        Email: email,
        Password: password,
        ConfirmPassword: confirmPassword,
        Name: name
    };


    $.ajax({
        type: 'POST',
        dataType: "html",
        url: 'http://localhost:50209/GetAllFonts/WizardRegister',
        data: AddAntiForgeryToken(wizardRegisterJsonRequest),
        beforeSend: function () {
            $('#create_account_form').data('busy', true);
            $('#create_account_busy').show();
        },
        success: function (data) {
            if (data.Success === true) {
                // all good here
            }

            $('#create_account_validation_summary').text(data.Message);
            $('#create_account_validation_summary').show();
        },
        complete: function () {
            $('#create_account_form').data('busy', false);
            $('#create_account_busy').hide();
        }
    });

    AddAntiForgeryToken = function (data) {
            alert("adding anti forgery");
          data.__RequestVerificationToken = $('#anti_forgery_token').val();
          return data;
    };

Controller code :

    [ValidateAntiForgeryToken]
    [HttpPost]
    public JsonResult WizardRegister(User usrDetails)
    //public JsonResult WizardLogOn(User usr)
    {
        // string test = ""; // this method WizardRegister is not getting called
    }

User model :

public class User
{
    public string Email { get; set; }
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
    public string __RequestVerificationToken { get; set; }
}

I am not sure if I need __RequestVerificationToken in the User model. I am using AntiForgery for the first time.

Please let me know where I am going wrong ...

Thanks, Rohan.

Update :

View / form code :

@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "create_account_form" }))
{
    @Html.AntiForgeryToken()
    <fieldset>
        <div class="input-fixed">
            <span class="mandatory_wizard">* </span>
            <input type="text" id="registrName" name="registrName" value="rohan" class="name" placeholder="Name">
        </div>
        <div class="input-fixed">
            <span class="mandatory_wizard">* </span>
            <input type="text" id="registrEmail" name="registrEmail" class="email" value="[email protected]" placeholder="Email">
        </div>
        <div class="input-fixed">
            <span class="mandatory_wizard">&nbsp; </span>
            <input type="text" class="phone" placeholder="Phone Number">
        </div>
        <div class="input-fixed">
            <span class="mandatory_wizard">* </span>
            <input type="password" id="registerPassword" name="registerPassword" value="12345678" class="password" placeholder="Password: Must be longer than 8 characters.">
        </div>
        <div class="input-fixed">
            <span class="mandatory_wizard">* </span>
            <input type="password" id="registerConfirmPassword" name="registerConfirmPassword" value="12345678" class="confirm-password" placeholder="Confirm Password">
        </div>
        <input type="submit" class="btn-modal-login" value="Create your account &gt;&gt;">
        <img id="create_account_busy" style="display: none;" src="./Launch Campaign _ Teeyoot_files/busy.gif" alt="Loading...">
    </fieldset>
}

Solution

  • @Html.AntiForgeryToken() generates a hidden input with name="__RequestVerificationToken". (it does not have an id attribute so $('#anti_forgery_token').val(); will return undefined.

    You can access the value using

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

    However, I strongly suggest you generate the inputs for your properties using the HtmlHelper methods (@Html.TextBoxFor(m => m.Name), @Html.PasswordFor(m => m.Password) etc) rather than generating manual html and then you can simply use

    data: $('form').serialize()
    

    in the ajax call (and you can then delete most of your script). You should also not be hard coding the url (it will fail as soon as you put it into production). Your script simply needs to be

    $.ajax({
        type: 'POST',
        dataType: "html",
        url: '@Url.Action("WizardRegister", "GetAllFonts")', 
        data: $('form').serialize(),
        beforeSend: function () {
            ....
    

    You should also be including @Html.ValidationMessageFor() for each property to get client side validation so invalid forms are not submitted.

    Side note: Its not clear from your code why you would use ajax. If the user is registering, then you would want to redirect if successful (and display validation errors if not), so ajax is pointless