Could anyone help to solve a problem? I'm trying to send data form from authorize user to protected controller method, using fetch and getting 400 error. I'm using NET CORE 5 MVC and on front-en bootstrap 5. If I remove ValidateAntiForgeryToken from AddItemToStore method I'm getting 415 error
C# code
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddItemToStore([FromBody] StoreUser itemsStore)
{
StoreUser str = new StoreUser
{
Id = 1,
UserId = itemsStore.UserId,
CatrgoryId = itemsStore.CatrgoryId
};
return Ok(str);
}
JS-code
var buttonAddOrder = document.getElementById("addToOrder");
buttonAddOrder?.addEventListener("click", function () {
var catId = document.querySelector("#formToStore input[name = 'cardId']").value;
var userId = document.querySelector("#formToStore input[name = 'userId']").value;
var antiForgeryToken = document.querySelector("#formToStore input[name = '__RequestVerificationToken']").value;
var itemsStore = {
__RequestVerificationToken: antiForgeryToken,
UserId: userId,
CatrgoryId: catId,
Payed: false
};
var url = "/CategoriesToUser/AddItemToStore";
var response = fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8;'
},
body: {
itemsStore: itemsStore
}
})
.then((response) => {
return response.json();
}).catch((e) => console.log(e.message));
console.log('buttonAddOrder', response);
HTML
<form id="formToStore" method="post" enctype="multipart/form-data">
<input type="hidden" name="cardId" id="cardId" /> @{ var getUser = await UserManager.GetUserAsync(User); }
<input type="hidden" name="userId" asp-for="@getUser.Id" />
<div >
<button type="button" id="buttonclose" name="buttonclose" data-bs-dismiss="modal">Close</button>
<button type="button" id="addToOrder" name="addToOrder" >
Add to Order
</button>
</div>
</form>
An attempt of using FormData doesn't work, the same error.
buttonAddOrder?.addEventListener("click", function () {
var url = "/CategoriesToUser/AddItemToStore";
const formToStore = document.getElementById('formToStore');
var formOrder = new FormData(formToStore);
let response = fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8;'
},
body: formOrder
})
.then((response) => {
return response.json();
}).catch((e) => console.log(e.message));
console.log('buttonAddOrder', response);
});
But If I send data to anonymous post method without using ValidateAntiForgeryToken on beck-end It's work. Example:
[AllowAnonymous]
[HttpPost]
public IActionResult AddItemToStore([FromBody] StoreUser itemsStore)
{
StoreUser str = new StoreUser
{
Id = 1,
UserId = itemsStore.UserId,
CatrgoryId = itemsStore.CatrgoryId
};
return Ok(str);
}
Screenshots
CodePudding user response:
Before coding, you need be sure the following inputs contain value:
<input type="hidden" name="cardId" id="cardId" /> @{ var getUser = await UserManager.GetUserAsync(User); }
<input type="hidden" name="userId" asp-for="@getUser.Id" />
Two ways you could follow:
1.From Body:
View
<form id="formToStore" method="post" enctype="multipart/form-data">
<input type="hidden" name="cardId" id="cardId" value="1" />
<input type="hidden" name="userId" value="466788cb-6aab-4798-81f1-f6b05cb71e32"/>
<div >
<button type="button" id="buttonclose" name="buttonclose" data-bs-dismiss="modal">Close</button>
<button type="button" id="addToOrder" name="addToOrder" >Add to Order</button>
</div>
</form>
@section Scripts
{
<script>
var buttonAddOrder = document.getElementById("addToOrder");
buttonAddOrder?.addEventListener("click", function () {
var catId = document.querySelector("#formToStore input[name = 'cardId']").value;
var userId = document.querySelector("#formToStore input[name = 'userId']").value;
var antiForgeryToken = document.querySelector("#formToStore input[name = '__RequestVerificationToken']").value;
var itemsStore = {
// __RequestVerificationToken: antiForgeryToken, //remove this....
UserId:userId,
CatrgoryId: catId,
Payed: false
};
var url = "/CategoriesToUser/AddItemToStore";
var response = fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json', //change here...
"X-ANTI-FORGERY-TOKEN": antiForgeryToken, //add this.....
},
body: JSON.stringify(itemsStore) //change here.....
})
.then((response) => {
return response.json();
}).catch((e) => console.log(e.message));
})
</script>
}
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddItemToStore([FromBody] StoreUser itemsStore)
{
//do your stuff....
return Ok(itemsStore);
}
Startup.cs:
services.AddAntiforgery(x => x.HeaderName = "X-ANTI-FORGERY-TOKEN");
2.From Form:
View
<form id="formToStore" method="post" enctype="multipart/form-data">
@*change name="cardId" to name="CatrgoryId"*@
<input type="hidden" name="CatrgoryId" id="cardId" value="1" />
<input type="hidden" name="userId" value="466788cb-6aab-4798-81f1-f6b05cb71e32"/>
<div >
<button type="button" id="buttonclose" name="buttonclose" data-bs-dismiss="modal">Close</button>
<button type="button" id="addToOrder" name="addToOrder" >Add to Order</button>
</div>
</form>
@section Scripts
{
<script>
var buttonAddOrder = document.getElementById("addToOrder");
buttonAddOrder?.addEventListener("click", function () {
var url = "/CategoriesToUser/AddItemToStore";
const formToStore = document.getElementById('formToStore');
var formOrder = new FormData(formToStore);
let response = fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
//headers: {
// 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8;'
//}, //don't need to set the Content-Type header
body: formOrder
})
.then((response) => {
return response.json();
}).catch((e) => console.log(e.message));
})
</script>
}
Controller
Change [FromBody]
to [FromForm]
.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult AddItemToStore([FromForm] StoreUser itemsStore)
{
//do your stuff...
return Ok(itemsStore);
}