Merlin04
Merlin04

Reputation: 2317

How do I use ValidateAntiForgeryToken in an HTTP GET request in ASP.NET Core?

Normally you use ValidateAntiForgeryToken with HttpPost, like this:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ...

I want to use ValidateAntiForgeryToken without HttpPost so that I can pass the token in as a URL parameter. How can I do this? Will it just work without HttpPost, and if so, what's the name of the parameter?

Upvotes: 5

Views: 15388

Answers (3)

Satinder singh
Satinder singh

Reputation: 10198

You need to add header in your ajax request using RequestVerificationToken, as written below, which takes hidden field value. This hidden field is autogenerated if your page has form tag with post method.

$.ajax({
    type: "GET",
    url: "api/YourCustomMethod",
    headers: {
        "RequestVerificationToken":
            $('input:hidden[name="__RequestVerificationToken"]').val()
    },                    
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: OnSuccess,
    error: OnErrorCall
});

If your page doesn't have form tag, then you have to call @Html.AntiForgeryToken() on page, which generate RequestVerificationToken


You method would something like this

[HttpGet]
[ValidateAntiForgeryToken]
public IActionResult GetABC()
{
    // your logic
}

And this can be verify when you run api url directly from browser, you will get error message like this "{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"Bad Request","status":400,"traceId":"|f27cc9e8-434210ecb10deb2f."}"

Upvotes: 2

Nicko
Nicko

Reputation: 186

With ASP.NET Core 3.1 things seem to be a lot easier.

All you have to do is pass a "RequestVerificationToken" header in the AJAX-call:

let token = $('input[name="__RequestVerificationToken"]').val();
let headers = { "RequestVerificationToken": token };
$.ajax({ ..., type: 'GET', headers: headers, ... });

For POST-calls, the token can be passed via the object in the body (or the FormData) as a "__RequestVerificationToken" field:

let postData["__RequestVerificationToken"] = token;
$.ajax({ ..., type: 'POST', data: postData, ... });

The method in the controller may be defined as follows:

[ValidateAntiForgeryToken]
public IActionResult GetNotifications()
{
    var notifications = _notificationService.GetNotifications();
    return Json(notifications);
}

Make sure the AntiforgeryOptions.HeaderName and AntiforgeryOptions.FormFieldName are not modified, otherwise change the names above with the respective values.

Upvotes: 6

Merlin04
Merlin04

Reputation: 2317

It's a bit complicated, but possible.

First, you need to use dependency injection to get a few things:

private readonly IAntiforgery _antiforgery;
private readonly AntiforgeryOptions _options;

public YourController(IAntiforgery antiforgery, IOptions<AntiforgeryOptions> optionsAccessor)
{
    _antiforgery = antiforgery;
    _options = optionsAccessor.Value;
}

Then, you can modify your action to add this code:

public IActionResult YourAction(string parameter1, string requestToken)
{
    // Begin antiforgery token validation
    typeof(DefaultAntiforgery).GetMethod("CheckSSLConfig", BindingFlags.NonPublic | BindingFlags.Instance)
        ?.Invoke(_antiforgery, new object[] { HttpContext }); 
    var tokens = new AntiforgeryTokenSet(requestToken, HttpContext.Request.Cookies[_options.Cookie.Name], _options.FormFieldName, _options.HeaderName);
    if (tokens.CookieToken == null)
    {
        throw new AntiforgeryValidationException("Cookie token cannot be null");
    }

    if (tokens.RequestToken == null)
    {
        throw new AntiforgeryValidationException("Request token cannot be null");
    }
    typeof(DefaultAntiforgery).GetMethod("ValidateTokens", BindingFlags.NonPublic | BindingFlags.Instance)
        ?.Invoke(_antiforgery, new object[] { HttpContext, tokens });
    // End antiforgery token validation

    return Content(parameter1);
}

This is essentially the same code that is run when you call IAntiforgery.ValidateRequestAsync, but modified to manually create the AntiforgeryTokenSet instead of just calling IAntiforgeryTokenStore.GetRequestTokensAsync. This means that you can get the request token from anywhere (in this case a URL parameter), not just from the form data of the POST request.

Upvotes: 1

Related Questions