Reputation: 2317
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
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
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
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