zoukankan      html  css  js  c++  java
  • .NET Core 屏蔽重复提交

    加入session支持

    public void ConfigureServices(IServiceCollection services)
    {
        // add session support
        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => false;
            options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
        });
    
        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromSeconds(100);
            options.Cookie.HttpOnly = true;
            options.Cookie.IsEssential = true;
        });
    
        // 没有下面这句,启动会失败,
        // 报这个错: InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' while attempting to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore
        services.AddDistributedMemoryCache();
        // 因为PreventDoublePostAttribute用到了IAntiforgery,所以这里还要加
        services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
        ...
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)
    {
        ...
        app.UseStaticFiles();
        // add session pipepline
        app.UseSession();
        ...
    }
    

    引入PreventDoublePostAttribute属性

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class PreventDoublePostAttribute : ActionFilterAttribute
    {
        private const string UniqFormuId = "LastProcessedToken";
        public override async void OnActionExecuting(ActionExecutingContext context)
        {
            IAntiforgery antiforgery = context.HttpContext.RequestServices.GetService(typeof(IAntiforgery)) as IAntiforgery;
    
            if (antiforgery == null)
                return;
    
            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();
        }
    }
    

    使用

    [HttpPost]
    [PreventDoublePost]
    public ActionResult<TodoItem> Create([FromForm] TodoItem item)
    {
        AllItems.Add(item);
        return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
    }
    

    测试

    # test post 
    POST https://localhost:44352/TodoItem/ HTTP/1.1
    content-type: application/x-www-form-urlencoded
    cache-control: no-cache
    
    __RequestVerificationToken=form_id_1
    &id=86336
    &Summary=ttt
    ###
    

    既然PreventDoublePostAttribute属性只使用了tokens.FormFieldName,那么hardcode一个hidden formid应该也可以,这样就不需要AntiForgery了。
    再说AntiForgery也不是这么用的。

    参考

    --------------------------- 知道的更多,不知道的也更多 ---------------------------
  • 相关阅读:
    HTTP协议入门
    TCP/IP的分层管理
    TCP与UDP
    如何处理某个Web页面的HTTP请求
    AGC005D ~K Perm Counting
    “玲珑杯” 线上赛Round #17 B 震惊,99%+的中国人都会算错的问题
    bzoj4455 [Zjoi2016]小星星
    AGC010F Tree Game
    AGC016E Poor Turkeys
    AGC003E Sequential operations on Sequence
  • 原文地址:https://www.cnblogs.com/mryux/p/15434744.html
Copyright © 2011-2022 走看看