diff --git a/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml b/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml
index bbbc22238..e0d8e06e4 100644
--- a/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml
+++ b/src/Plugins/Theme.Modern/Views/Modern/Shared/_Layout.cshtml
@@ -19,6 +19,7 @@
@await RenderSectionAsync("head", false)
+@Html.AntiForgeryToken()
@await Component.InvokeAsync("Widget", new { widgetZone = "body_start_html_tag_after" })
diff --git a/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs b/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs
index 5b5afee97..6521f45ef 100644
--- a/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs
+++ b/src/Web/Grand.Web.Common/Controllers/BasePublicController.cs
@@ -8,6 +8,7 @@ namespace Grand.Web.Common.Controllers;
[ClosedStore]
[Language]
[Affiliate]
+[AutoValidateAntiforgeryToken]
[SharedKernel.Attributes.ApiController]
public abstract class BasePublicController : BaseController
{
diff --git a/src/Web/Grand.Web/Controllers/AccountController.cs b/src/Web/Grand.Web/Controllers/AccountController.cs
index 8169012a0..683cfe44e 100644
--- a/src/Web/Grand.Web/Controllers/AccountController.cs
+++ b/src/Web/Grand.Web/Controllers/AccountController.cs
@@ -195,7 +195,6 @@ public virtual IActionResult Login(bool? checkoutAsGuest)
//available even when navigation is not allowed
[PublicStore(true)]
[ClosedStore(true)]
- [AutoValidateAntiforgeryToken]
[IgnoreApi]
public virtual async Task Login(LoginModel model, string returnUrl)
{
@@ -367,7 +366,6 @@ public virtual IActionResult PasswordRecovery()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[PublicStore(true)]
public virtual async Task> PasswordRecovery(PasswordRecoveryModel model)
{
@@ -400,7 +398,6 @@ public virtual async Task> PasswordRe
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
//available even when navigation is not allowed
[PublicStore(true)]
public virtual async Task PasswordRecoveryConfirm(PasswordRecoveryConfirmModel model)
@@ -447,7 +444,6 @@ public virtual async Task> Register()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
//available even when navigation is not allowed
[PublicStore(true)]
public virtual async Task Register(RegisterModel model, string returnUrl)
@@ -570,7 +566,6 @@ public virtual IActionResult RegisterResult(int resultId)
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
//available even when navigation is not allowed
[PublicStore(true)]
public virtual async Task CheckUsernameAvailability(string username)
@@ -647,7 +642,6 @@ public virtual async Task> Info()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task> Info(CustomerInfoModel model)
{
@@ -683,7 +677,6 @@ await _mediator.Send(new UpdateCustomerInfoCommand {
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task RemoveExternalAssociation(string id,
[FromServices] IExternalAuthenticationService openAuthenticationService)
@@ -733,7 +726,6 @@ public virtual async Task> Addresses()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task AddressDelete(string addressId)
{
@@ -776,7 +768,6 @@ public virtual async Task> AddressAdd()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task> AddressAdd(CustomerAddressEditModel model,
[FromServices] AddressSettings addressSettings)
@@ -841,7 +832,6 @@ public virtual async Task> AddressEdit(st
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task> AddressEdit(CustomerAddressEditModel model,
[FromServices] AddressSettings addressSettings)
@@ -929,7 +919,6 @@ public virtual async Task ChangePassword()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task ChangePassword(ChangePasswordModel model)
{
@@ -965,7 +954,6 @@ public virtual IActionResult DeleteAccount()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task DeleteAccount(DeleteAccountModel model)
{
@@ -1152,7 +1140,6 @@ public virtual async Task SubAccountAdd()
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task SubAccountAdd(SubAccountCreateModel model)
{
@@ -1184,7 +1171,6 @@ public virtual async Task SubAccountEdit(string id)
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task SubAccountEdit(SubAccountEditModel model)
{
@@ -1203,7 +1189,6 @@ public virtual async Task SubAccountEdit(SubAccountEditModel mode
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task SubAccountDelete(string id)
{
diff --git a/src/Web/Grand.Web/Controllers/BlogController.cs b/src/Web/Grand.Web/Controllers/BlogController.cs
index 7fa0f9adb..083bcf71e 100644
--- a/src/Web/Grand.Web/Controllers/BlogController.cs
+++ b/src/Web/Grand.Web/Controllers/BlogController.cs
@@ -130,7 +130,6 @@ await permissionService.Authorize(StandardPermission.ManageBlog))
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task> BlogPost(AddBlogCommentModel model,
[FromServices] IAclService aclService)
diff --git a/src/Web/Grand.Web/Controllers/CatalogController.cs b/src/Web/Grand.Web/Controllers/CatalogController.cs
index 0ba64bc6b..953f1b310 100644
--- a/src/Web/Grand.Web/Controllers/CatalogController.cs
+++ b/src/Web/Grand.Web/Controllers/CatalogController.cs
@@ -318,7 +318,6 @@ public virtual async Task VendorAll(VendorPagingModel command)
#region Vendor reviews
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task VendorReviews(VendorReviewsModel model)
{
diff --git a/src/Web/Grand.Web/Controllers/ContactController.cs b/src/Web/Grand.Web/Controllers/ContactController.cs
index c45557336..206ebc5ef 100644
--- a/src/Web/Grand.Web/Controllers/ContactController.cs
+++ b/src/Web/Grand.Web/Controllers/ContactController.cs
@@ -59,7 +59,6 @@ public virtual async Task> Index(
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[ClosedStore(true)]
[DenySystemAccount]
public virtual async Task> Index(
diff --git a/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs b/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs
index de16e61d0..353165f54 100644
--- a/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs
+++ b/src/Web/Grand.Web/Controllers/KnowledgebaseController.cs
@@ -264,7 +264,6 @@ private async Task PrepareKnowledgebaseArticleModel(KnowledgebaseArticleModel mo
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task ArticleCommentAdd(KnowledgebaseArticleModel model,
[FromServices] ICustomerService customerService)
diff --git a/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs b/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs
index a8cebfab4..61e0fd2a8 100644
--- a/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs
+++ b/src/Web/Grand.Web/Controllers/MerchandiseReturnController.cs
@@ -138,7 +138,6 @@ public virtual async Task MerchandiseReturn(string orderId)
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
public virtual async Task MerchandiseReturn(MerchandiseReturnModel model)
{
var order = await _orderService.GetOrderById(model.OrderId);
diff --git a/src/Web/Grand.Web/Controllers/NewsController.cs b/src/Web/Grand.Web/Controllers/NewsController.cs
index 5851d33be..2b7694469 100644
--- a/src/Web/Grand.Web/Controllers/NewsController.cs
+++ b/src/Web/Grand.Web/Controllers/NewsController.cs
@@ -91,7 +91,6 @@ await _permissionService.Authorize(StandardPermission.ManageNews))
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task NewsCommentAdd(AddNewsCommentModel model)
{
diff --git a/src/Web/Grand.Web/Controllers/OrderController.cs b/src/Web/Grand.Web/Controllers/OrderController.cs
index 883634f00..647be5489 100644
--- a/src/Web/Grand.Web/Controllers/OrderController.cs
+++ b/src/Web/Grand.Web/Controllers/OrderController.cs
@@ -135,7 +135,6 @@ public virtual async Task GetPdfInvoice(string orderId, [FromServ
//My account / Order details page / Add order note
[HttpPost]
- [AutoValidateAntiforgeryToken]
public virtual async Task> AddOrderNote(AddOrderNoteModel model)
{
if (!_orderSettings.AllowCustomerToAddOrderNote)
@@ -174,7 +173,6 @@ public virtual async Task ReOrder(string orderId)
//My account / Order details page / Complete payment
[HttpPost]
- [AutoValidateAntiforgeryToken]
public virtual async Task RePostPayment(string orderId)
{
var order = await _orderService.GetOrderById(orderId);
diff --git a/src/Web/Grand.Web/Controllers/ProductController.cs b/src/Web/Grand.Web/Controllers/ProductController.cs
index 6e45d6a83..d751d31c3 100644
--- a/src/Web/Grand.Web/Controllers/ProductController.cs
+++ b/src/Web/Grand.Web/Controllers/ProductController.cs
@@ -136,7 +136,6 @@ public virtual async Task NewProducts()
#region Email a friend
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task ProductEmailAFriend(ProductEmailAFriendModel model)
{
@@ -180,7 +179,6 @@ await _mediator.Send(new SendProductEmailAFriendMessageCommand {
#region Ask question
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task AskQuestionOnProduct(ProductAskQuestionSimpleModel model)
{
@@ -549,7 +547,6 @@ public virtual async Task QuickView(string productId)
#region Product reviews
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task ProductReviews(
ProductReviewsModel model)
diff --git a/src/Web/Grand.Web/Controllers/ShoppingCartController.cs b/src/Web/Grand.Web/Controllers/ShoppingCartController.cs
index 3f28df28c..e1fc0fd35 100644
--- a/src/Web/Grand.Web/Controllers/ShoppingCartController.cs
+++ b/src/Web/Grand.Web/Controllers/ShoppingCartController.cs
@@ -301,7 +301,6 @@ public async Task> CartTotal()
}
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
[HttpPost]
public virtual async Task UpdateQuantity(UpdateQuantityModel model)
@@ -497,7 +496,6 @@ public virtual async Task StartCheckout(CheckoutAttributeSelected
return RedirectToRoute("LoginCheckoutAsGuest", new { returnUrl = Url.RouteUrl("ShoppingCart") });
}
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
[HttpPost]
public virtual async Task ApplyDiscountCoupon(DiscountCouponModel model)
@@ -541,7 +539,6 @@ await _customerService.UpdateUserField(_contextAccessor.WorkContext.CurrentCusto
});
}
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
[HttpPost]
public virtual async Task ApplyGiftVoucher(GiftVoucherCouponModel model)
@@ -586,7 +583,6 @@ await _customerService.UpdateUserField(_contextAccessor.WorkContext.CurrentCusto
});
}
- [AutoValidateAntiforgeryToken]
[HttpPost]
public virtual async Task GetEstimateShipping(EstimateShippingModel model)
{
diff --git a/src/Web/Grand.Web/Controllers/VendorController.cs b/src/Web/Grand.Web/Controllers/VendorController.cs
index 4b7efcdaf..7f2c04cf2 100644
--- a/src/Web/Grand.Web/Controllers/VendorController.cs
+++ b/src/Web/Grand.Web/Controllers/VendorController.cs
@@ -128,7 +128,6 @@ public virtual async Task ApplyVendor()
[HttpPost]
[ActionName("ApplyVendor")]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
[CustomerGroupAuthorize(SystemCustomerGroupNames.Registered)]
public virtual async Task ApplyVendorSubmit(ApplyVendorModel model, [FromServices] ISeNameService seNameService)
@@ -195,7 +194,6 @@ await _messageProviderService.SendNewVendorAccountApplyStoreOwnerMessage(_contex
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task ContactVendor(ContactVendorModel model)
{
diff --git a/src/Web/Grand.Web/Controllers/WishlistController.cs b/src/Web/Grand.Web/Controllers/WishlistController.cs
index 050c6bf34..9965c0485 100644
--- a/src/Web/Grand.Web/Controllers/WishlistController.cs
+++ b/src/Web/Grand.Web/Controllers/WishlistController.cs
@@ -111,7 +111,6 @@ public virtual async Task> Index(Guid? customerGuid)
return View(model);
}
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
[HttpPost]
public virtual async Task UpdateQuantity(UpdateQuantityModel model)
@@ -208,7 +207,6 @@ public virtual async Task DeleteItemFromWishlist(string shoppingC
}
[HttpPost]
- [AutoValidateAntiforgeryToken]
[DenySystemAccount]
public virtual async Task EmailWishlist(WishlistEmailAFriendModel model,
[FromServices] IMessageProviderService messageProviderService,
diff --git a/src/Web/Grand.Web/Views/Shared/_Layout.cshtml b/src/Web/Grand.Web/Views/Shared/_Layout.cshtml
index 104332ff4..51951c577 100644
--- a/src/Web/Grand.Web/Views/Shared/_Layout.cshtml
+++ b/src/Web/Grand.Web/Views/Shared/_Layout.cshtml
@@ -19,6 +19,7 @@
@await RenderSectionAsync("head", false)
+@Html.AntiForgeryToken()
diff --git a/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml b/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml
index 8fc177288..9400d4a11 100644
--- a/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml
+++ b/src/Web/Grand.Web/Views/Shared/_LayoutPopup.cshtml
@@ -15,6 +15,7 @@
+@Html.AntiForgeryToken()
@RenderBody()
diff --git a/src/Web/Grand.Web/wwwroot/theme/script/public.common.js b/src/Web/Grand.Web/wwwroot/theme/script/public.common.js
index 49776e565..7c881fd3e 100644
--- a/src/Web/Grand.Web/wwwroot/theme/script/public.common.js
+++ b/src/Web/Grand.Web/wwwroot/theme/script/public.common.js
@@ -12,6 +12,28 @@ function addAntiForgeryToken(data) {
return data;
};
+//attach the CSRF token as a header to every AJAX request (axios and jQuery),
+//so requests are covered regardless of body type (json/form/FormData)
+(function () {
+ const tokenInput = document.querySelector('input[name=__RequestVerificationToken]');
+ if (!tokenInput) {
+ return;
+ }
+ const token = tokenInput.value;
+
+ if (typeof axios !== 'undefined') {
+ axios.defaults.headers.common['X-CSRF-TOKEN'] = token;
+ }
+
+ if (typeof $ !== 'undefined' && typeof $.ajaxSetup === 'function') {
+ $.ajaxSetup({
+ beforeSend: function (xhr) {
+ xhr.setRequestHeader('X-CSRF-TOKEN', token);
+ }
+ });
+ }
+})();
+
// runs an array of async functions in sequential order
function seq(arr, callback, index) {
// first call, without an index