.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也不是这么用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值