加入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也不是这么用的。
参考
---------------------------
知道的更多,不知道的也更多
---------------------------
标签:
asp.net mvc
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具