gpt4 book ai didi

asp.net-mvc - 如何在不使用 Javascript 的情况下防止 .NET MVC 中的多个表单提交?

转载 作者:行者123 更新时间:2023-12-03 05:58:19 25 4
gpt4 key购买 nike

我想防止用户在 .NET MVC 中多次提交表单。我已经尝试了几种使用 Javascript 的方法,但很难让它在所有浏览器中工作。那么,如何在我的 Controller 中防止这种情况发生呢?有什么方法可以检测到多次提交吗?

最佳答案

更新了 ASP.NET Core MVC(.NET Core 和 .NET 5.0)的答案

更新说明:记住 ASP.NET Core 是 still called "Core" in .NET 5.0 .

我将像以前一样坚持影响最小的用例,您只装饰那些您特别想要防止重复请求的 Controller 操作。如果您想让这个过滤器在每个请求上运行,或者想使用异步,还有其他选项。请参阅this article了解更多详情。

新的表单标记帮助程序现在自动包含 AntiForgeryToken,因此您不再需要手动将其添加到 View 中。

像本例一样创建一个新的ActionFilterAttribute。您可以用它做许多其他事情,例如包括时间延迟检查,以确保即使用户提供两个不同的 token ,他们也不会每分钟提交多次。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class PreventDuplicateRequestAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext context) {
if (context.HttpContext.Request.HasFormContentType && context.HttpContext.Request.Form.ContainsKey("__RequestVerificationToken")) {
var currentToken = context.HttpContext.Request.Form["__RequestVerificationToken"].ToString();
var lastToken = context.HttpContext.Session.GetString("LastProcessedToken");

if (lastToken == currentToken) {
context.ModelState.AddModelError(string.Empty, "Looks like you accidentally submitted the same form twice.");
}
else {
context.HttpContext.Session.SetString("LastProcessedToken", currentToken);
}
}
}
}

应要求,我还写了一个异步版本which can be found here .

以下是自定义 PreventDuplicateRequest 属性的人为使用示例。

[HttpPost]
[ValidateAntiForgeryToken]
[PreventDuplicateRequest]
public IActionResult Create(InputModel input) {
if (ModelState.IsValid) {
// ... do something with input

return RedirectToAction(nameof(SomeAction));
}

// ... repopulate bad input model data into a fresh viewmodel

return View(viewModel);
}

测试注意事项:仅在浏览器中回击不会使用相同的 AntiForgeryToken。在速度更快的计算机上,您无法双击该按钮两次,您需要使用类似 Fiddler 的工具。使用相同的 token 多次重放您的请求。

设置注意事项:Core MVC 默认情况下不启用 session 。您需要将 Microsoft.AspNet.Session 包添加到您的项目中,并正确配置 Startup.cs。请阅读this article了解更多详情。

session 设置的简短版本是:在 Startup.ConfigureServices() 中,您需要添加:

services.AddDistributedMemoryCache();
services.AddSession();

Startup.Configure() 中,您需要添加(之前 app.UseMvc() !!):

app.UseSession();
<小时/>

ASP.NET MVC (.NET Framework 4.x) 的原始答案

首先,确保您在表单上使用 AntiForgeryToken。

然后你可以制作一个自定义的ActionFilter:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class PreventDuplicateRequestAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (HttpContext.Current.Request["__RequestVerificationToken"] == null)
return;

var currentToken = HttpContext.Current.Request["__RequestVerificationToken"].ToString();

if (HttpContext.Current.Session["LastProcessedToken"] == null) {
HttpContext.Current.Session["LastProcessedToken"] = currentToken;
return;
}

lock (HttpContext.Current.Session["LastProcessedToken"]) {
var lastToken = HttpContext.Current.Session["LastProcessedToken"].ToString();

if (lastToken == currentToken) {
filterContext.Controller.ViewData.ModelState.AddModelError("", "Looks like you accidentally tried to double post.");
return;
}

HttpContext.Current.Session["LastProcessedToken"] = currentToken;
}
}
}

在您的 Controller 操作中,您只需...

[HttpPost]
[ValidateAntiForgeryToken]
[PreventDuplicateRequest]
public ActionResult CreatePost(InputModel input) {
...
}

您会注意到这并不会完全阻止请求。相反,它会在 modelstate 中返回一个错误,因此当您的操作检查 ModelState.IsValid 时,它会发现它不是,并将返回正常的错误处理。

关于asp.net-mvc - 如何在不使用 Javascript 的情况下防止 .NET MVC 中的多个表单提交?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4250604/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com