0

I'm trying to imlement the CSRF token into my code, so far without luck. I've figured there are three steps:

My code for the form to be sent:

@using (Html.BeginForm("Manage", "Account"))
{
    @Html.AntiForgeryToken()
}

In my controller view I have written:

public class HomeController : Controller
    {
    [HttpPost]
    [ValidateAntiForgeryToken] 

public ActionResult Index()
    {

        return View("Table");
    } 
    etc...
    }

and my ajax call:

$.ajax({
            type: "POST",
            url: "../Home/" + sFunction,
            contentType: "application/json; charset=utf-8",
            processData: false,
            dataType: "json",
            headers: { "__RequestVerificationToken": 
            $('input[name=__RequestVerificationToken]').val() },
            data: data === null ? null : JSON.stringify(data),

etc.

What am I missing? why is it not working? Thanks

Joe Joe Joe
  • 79
  • 1
  • 15
  • Hi Joe,Kindly follow below link https://stackoverflow.com/questions/4074199/jquery-ajax-calls-and-the-html-antiforgerytoken – Ratheesh Jan 15 '19 at 11:18
  • Thank you, I have already checked that link, as well as others. I have not managed to resolve my problem – Joe Joe Joe Jan 15 '19 at 11:38
  • I think your Ajax POST call is explicitly initiated from a button click , pls confirm – Ratheesh Jan 15 '19 at 11:50
  • No, the Ajax call happens automatically on page load. It works without the Anti forgery token. Thanks – Joe Joe Joe Jan 15 '19 at 11:53
  • @JoeJoeJoe '[ValidateAntiForgeryToken] ' needs to decorate your form post method. Not your index GET method – Sean T Jan 15 '19 at 11:57
  • Well, there are a number of issues here. First, the method you show here is your Home/Index method, but the method you post to is Account/Manage. Your ajax method uses a relative address that may or may not be accurate depending on the actual URL being used ("/", "/Home" or "/Home/Index" will all have different results) – Erik Funkenbusch Jan 15 '19 at 13:20

1 Answers1

2

[ValidateAntiForgeryToken] needs to decorate your form post method. Not your index GET method. In this case...

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Manage(YourViewModel model)
{
    //do your logic

    return View(//whatever route & model)
}

and in your js you add this to your data object.

let form = //get your form control here
let data = $(form).serialize();//form is your form control
data.__RequestVerificationToken = $('input[name=__RequestVerificationToken]').val();

$.ajax({
        type: "POST",
        url: //controller/action,
        contentType: "application/x-www-form-urlencoded",
        processData: false,
        dataType: "json",
        data: JSON.stringify(data),
        //etc....
});
Sean T
  • 2,414
  • 2
  • 17
  • 23
  • Thanks! is the form post method supposed to be empty? (public ActionResult Manage()) – Joe Joe Joe Jan 15 '19 at 12:52
  • no, you need to pop your forms viewmodel in there and then perform the logic. I've updated my answer @JoeJoeJoe – Sean T Jan 15 '19 at 12:53
  • I've read over half a dozen tutorials on anti forgery tokens and they just say to plop [ValidateAntiForgeryToken] down in the controller and it will work, none explain that there needs to be some sort of logic inside. ValidateAntiForgeryToken checks that the incoming request has the request verification cookie and the hidden request verification form field. Is that the logic I need to write inside? I wish there was something that explains this somewhere – Joe Joe Joe Jan 15 '19 at 13:53
  • @JoeJoeJoe `AntiForgeryTokens` only work with `POST` requests. It's redundant to have them with a `GET`. `GET`s retrieve data from the server. `POST`'s send data to the server. AFT's basically ensure that incoming data to the server is coming from a valid source. As for the logic, I was referring to whatever logic you yourself need to write to process the form... e.g, map and submit to a database – Sean T Jan 15 '19 at 14:13
  • Thanks for explaining, I get it now. There appears to be some other problem, even though I have specified that it should be sent as Json, it doesn't appear to be showing up when I throw in a break point in my controller. I think it defaults to sending it as a form if no content-type is specified, which I think is what it is doing. Will have to look into it deeper. – Joe Joe Joe Jan 15 '19 at 15:22
  • @JoeJoeJoe I'll update my answer with proper content-type. If it's a form just serialize it using `.serialize()` in js and change the content-type to `application/x-www-form-urlencoded` – Sean T Jan 15 '19 at 15:30