You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core如何限制AntiForgery Token单次使用并阻止无页面访问调用?

针对Razor Pages中AntiForgery Token的两个问题解决方案

一、阻止未访问页面就调用POST接口

微软原生的AntiForgery机制仅验证Token与Cookie的匹配性,不检查用户是否加载过目标页面。要实现该限制,需结合会话(Session)标记用户的页面访问状态:

  • 步骤1:启用Session服务
    在Program.cs中配置Session:

    builder.Services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(30);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    });
    
    // 在app.UseRouting()之后添加
    app.UseSession();
    
  • 步骤2:在页面的GET方法中标记访问状态

    public IActionResult OnGet()
    {
        // 标记用户已访问当前页面
        HttpContext.Session.SetString("HasVisitedTargetPage", "true");
        return Page();
    }
    
  • 步骤3:在POST方法中校验访问标记

    [ValidateAntiForgeryToken]
    public IActionResult OnPost()
    {
        // 检查是否已访问过页面
        if (HttpContext.Session.GetString("HasVisitedTargetPage") != "true")
        {
            return Forbid(); // 返回403禁止访问
        }
    
        // 执行业务逻辑
        return RedirectToPage("/Success");
    }
    

二、实现AntiForgery Token单次使用

微软没有现成的单次使用Token方案,需自行扩展,核心思路是在服务器端记录Token的使用状态,验证通过后立即失效:

基于Session的简单实现(适合单服务器场景)

  • 在GET方法中生成并存储Token:

    public IActionResult OnGet()
    {
        var antiForgery = HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
        var tokens = antiForgery.GetAndStoreTokens(HttpContext);
        // 将当前请求的Token存入Session
        HttpContext.Session.SetString("SingleUseAntiForgeryToken", tokens.RequestToken);
        return Page();
    }
    
  • 在POST方法中校验并销毁Token:

    [ValidateAntiForgeryToken]
    public async Task<IActionResult> OnPostAsync()
    {
        var antiForgery = HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
        try
        {
            // 先执行原生的AntiForgery验证
            await antiForgery.ValidateRequestAsync(HttpContext);
    
            // 获取请求中的Token和Session中存储的Token
            var requestToken = Request.Form["__RequestVerificationToken"];
            var storedToken = HttpContext.Session.GetString("SingleUseAntiForgeryToken");
    
            if (string.IsNullOrEmpty(storedToken) || storedToken != requestToken)
            {
                return Forbid();
            }
    
            // 验证通过后立即删除Session中的Token,禁止重复使用
            HttpContext.Session.Remove("SingleUseAntiForgeryToken");
        }
        catch
        {
            return Forbid();
        }
    
        // 业务逻辑处理
        return RedirectToPage("/Success");
    }
    

分布式场景优化

如果是多服务器部署的系统,建议用Redis等分布式缓存代替Session存储Token,避免Session无法跨节点共享的问题。核心逻辑一致:生成Token时存入缓存,验证时取出对比,通过后删除缓存。

注意事项

  • 两种方案可结合使用,既确保用户必须先访问页面,又保证Token仅能使用一次。
  • 会话或缓存的过期时间需合理设置,避免影响正常用户的操作体验。
  • 高并发场景下,要注意分布式缓存的性能和原子性操作(比如用Redis的DEL命令确保Token删除的原子性)。

内容的提问来源于stack exchange,提问作者Jun Yan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 00:46:04