'Use the ValidateAntiForgeryToken attribute with JSON POST data
Some of my controller methods have the [ValidateAntiForgeryToken]
attribute for the usual reasons. It's only app-internal actions, no cross-site API or similar. Now I replaced a request made from JavaScript from jQuery (which seems to send data as form fields) with a real JSON post using fetch()
directly. The __RequestVerificationToken
field was among the sent data so it must have ended up in a place where ASP.NET Core MVC was looking for it.
Now it's in the JSON body, there are no form fields anymore. And the request fails with code 400, probably due to the missing (not found) token.
I've searched for solutions but this has so far only been covered for the older non-Core ASP.NET from 10 years ago. Is it still possible today with current tools to send the token in the JSON body or as HTTP header (I'm fine with either one) and have it validated without much boilerplate code? I can add a special attribute class for that if needed. I already looked at the framework class but it doesn't do anything, this must be handled elsewhere.
Solution 1:[1]
Below is a work demo, you can refer to it. Read this to know more.
1.Customize AntiforgeryOptions in Program.cs:
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
});
2.Require antiforgery validation
public IActionResult Index()
{
// ...
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Privacy()
{
// ...
return View();
}
Index.cshtml:
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="@requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
@section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("@Url.Action("Privacy")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
result:
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Qing Guo |