.net core 中如何有效屏蔽重复提交

Posted Archy_Wang_1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.net core 中如何有效屏蔽重复提交相关的知识,希望对你有一定的参考价值。

一.咨询区

Guilherme Ferreira

我通过 post 方式向我的一个webapi中提交数据,然后插入到数据库中,在 ui端,当用户点击某一个 button 之后,代码会将 button 禁用,但因为某些原因,点击按钮的速度比禁用按钮的函数还要快,这就造成了post两次的情况,也就插入了两条同样的数据。

在客户端我用 axios 来做 post 提交,请问我如何在 server 端规避这种事情?

二.回答区

  • Christian Gollhardt

前段时间刚好遇到了这个场景,我创建了一个 ActionFilter,然后使用了 Anti Fogery Token ,参考如下代码:

首先启用 session。

services.Configure<CookiePolicyOptions>(options =>
                    {
                        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                        options.CheckConsentNeeded = Context => false;
                        options.MinimumSameSitePolicy = SameSiteMode.None;
                    });

services.AddMemoryCache();
                    services.AddSession(options => {
                        // Set a short timeout for easy testing.
                        options.IdleTimeout = TimeSpan.FromMinutes(10);
                        options.Cookie.HttpOnly = true;
                        // Make the session cookie essential
                        options.Cookie.IsEssential = true;
                    });

然后就可以 use 了。

 app.UseSession();

接下来定义一个防重复提交的 Attribute 。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class PreventDoublePostAttribute : ActionFilterAttribute
{
    private const string UniqFormuId = "LastProcessedToken";
    public override async void OnActionExecuting(ActionExecutingContext context)
    {

        IAntiforgery antiforgery = (IAntiforgery)context.HttpContext.RequestServices.GetService(typeof(IAntiforgery));
        AntiforgeryTokenSet tokens = antiforgery.GetAndStoreTokens(context.HttpContext);

        if (!context.HttpContext.Request.Form.ContainsKey(tokens.FormFieldName))
        {
            return;
        }

        var currentFormId = context.HttpContext.Request.Form[tokens.FormFieldName].ToString();
        var lastToken = "" + context.HttpContext.Session.GetString(UniqFormuId);

        if (lastToken.Equals(currentFormId))
        {
            context.ModelState.AddModelError(string.Empty, "Looks like you accidentally submitted the same form twice.");
            return;
        }
        context.HttpContext.Session.Remove(UniqFormuId);
        context.HttpContext.Session.SetString(UniqFormuId, currentFormId);
        await context.HttpContext.Session.CommitAsync();

    }

}

然后在需要该验证规则的 Action 上进行标注。

[HttpPost]
[PreventDoublePost]
public async Task<IActionResult> Edit(EditViewModel model)
{
    if (!ModelState.IsValid)
    {
        //PreventDoublePost Attribute makes ModelState invalid
    }
    throw new NotImplementedException();
}

关于如何生成 Anti Fogery Token,可以看下msdn: https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.2#javascript

三.点评区

这是一个非常常见的需求,除了这种做法,通常用带有过期时间的cache来做,也是可以的,比如 3s 内只能有一个请求。

以上是关于.net core 中如何有效屏蔽重复提交的主要内容,如果未能解决你的问题,请参考以下文章

.net core 中如何有效屏蔽重复提交

.net core 中如何有效屏蔽重复提交

.net core savechanges 网络不好情况下,如何防止用户连击重复提交数据?

需要一种有效的方法来避免使用 Laravel 5 重复代码片段

.net mvc如何防止用户后退,现在保存订单后能回到订单页面重复提交,如何能防止后退

如何多次提交表单(asp.net core razor)