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

.NET Framework WebForms遗留应用登录页限流实现咨询

.NET Framework WebForms登录页限流实现方案

一、使用ActionFilterAttribute实现限流

WebForms虽无.NET Core风格的Startup配置,但仍可通过自定义ActionFilterAttribute实现限流,支持局部标记或全局注册。

1. 自定义限流过滤器

创建继承自ActionFilterAttribute的类,在OnActionExecuting中实现核心限流逻辑:

using System;
using System.Web.Mvc;
using System.Web.Caching;

public class LoginRateLimitAttribute : ActionFilterAttribute
{
    // 可配置限流参数:1分钟内最多5次尝试
    public int MaxAttempts { get; set; } = 5;
    public int WindowSeconds { get; set; } = 60;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var request = filterContext.HttpContext.Request;
        // 以客户端IP作为限流标识,也可结合输入的用户名增强精度
        var cacheKey = $"LoginRateLimit_{request.UserHostAddress}";
        
        var cache = filterContext.HttpContext.Cache;
        var attempts = cache[cacheKey] as int? ?? 0;

        if (attempts >= MaxAttempts)
        {
            filterContext.Result = new ContentResult
            {
                Content = "登录尝试过于频繁,请稍后再试。",
                ContentType = "text/plain"
            };
            return;
        }

        // 更新缓存计数并设置过期时间
        cache.Insert(
            cacheKey,
            attempts + 1,
            null,
            DateTime.Now.AddSeconds(WindowSeconds),
            Cache.NoSlidingExpiration
        );

        base.OnActionExecuting(filterContext);
    }
}

2. 在登录事件中调用过滤器

WebForms页面事件默认不直接支持ActionFilter标记,可手动在cmdSubmit_Click中触发检查逻辑:

void cmdSubmit_Click(object sender, EventArgs e)
{
    // 初始化过滤器与上下文
    var rateLimitFilter = new LoginRateLimitAttribute();
    var httpContextWrapper = new HttpContextWrapper(HttpContext.Current);
    var filterContext = new ActionExecutingContext(
        new ControllerContext(httpContextWrapper, new RouteData(), new EmptyController()),
        new ActionDescriptor(),
        new System.Collections.Generic.Dictionary<string, object>()
    );

    // 执行限流检查
    rateLimitFilter.OnActionExecuting(filterContext);
    if (filterContext.Result != null)
    {
        lblError.Text = "登录尝试过于频繁,请稍后再试。";
        return;
    }

    // 原有登录验证逻辑
    // ...
}

// 辅助空控制器,用于构造ActionExecutingContext
public class EmptyController : Controller { }

3. 全局注册过滤器(可选)

若需对所有登录请求全局限流,在Global.asax的Application_Start中注册:

protected void Application_Start(object sender, EventArgs e)
{
    GlobalFilters.Filters.Add(new LoginRateLimitAttribute
    {
        MaxAttempts = 5,
        WindowSeconds = 60
    });
}

二、其他限流实现方案

1. 基于IHttpModule实现全局限流

通过自定义HttpModule拦截所有请求,针对登录请求执行限流:

using System;
using System.Web;
using System.Web.Caching;

public class LoginRateLimitModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += Context_BeginRequest;
    }

    private void Context_BeginRequest(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        var request = app.Context.Request;

        // 判断是否为登录页POST请求
        if (request.Path.Equals("/login.aspx", StringComparison.OrdinalIgnoreCase) && request.HttpMethod == "POST")
        {
            var cacheKey = $"LoginRateLimit_{request.UserHostAddress}";
            var cache = app.Context.Cache;
            var attempts = cache[cacheKey] as int? ?? 0;

            if (attempts >= 5)
            {
                app.Context.Response.Clear();
                app.Context.Response.StatusCode = 429;
                app.Context.Response.Write("登录尝试过于频繁,请稍后再试。");
                app.Context.Response.End();
                return;
            }

            cache.Insert(
                cacheKey,
                attempts + 1,
                null,
                DateTime.Now.AddSeconds(60),
                Cache.NoSlidingExpiration
            );
        }
    }

    public void Dispose() { }
}

在Web.config中注册Module:

<system.web>
  <httpModules>
    <add name="LoginRateLimitModule" type="YourNamespace.LoginRateLimitModule"/>
  </httpModules>
</system.web>
<!-- IIS集成模式需额外在system.webServer下注册 -->
<system.webServer>
  <modules>
    <add name="LoginRateLimitModule" type="YourNamespace.LoginRateLimitModule" preCondition="managedHandler"/>
  </modules>
</system.webServer>

2. 直接在登录事件中实现限流逻辑

无需额外组件,直接在cmdSubmit_Click中编写限流代码:

void cmdSubmit_Click(object sender, EventArgs e)
{
    var clientIp = HttpContext.Current.Request.UserHostAddress;
    var cacheKey = $"LoginAttempts_{clientIp}";
    var cache = HttpContext.Current.Cache;

    int attempts = cache[cacheKey] as int? ?? 0;

    if (attempts >= 5)
    {
        lblError.Text = "登录尝试过于频繁,请1分钟后再试。";
        return;
    }

    // 更新缓存计数与过期时间
    cache.Insert(
        cacheKey,
        attempts + 1,
        null,
        DateTime.Now.AddMinutes(1),
        Cache.NoSlidingExpiration
    );

    // 原有登录验证逻辑
    // ...
}

3. 分布式缓存适配(多服务器场景)

若应用为集群部署,本地缓存无法共享状态,可改用Redis等分布式缓存:

using StackExchange.Redis;

void cmdSubmit_Click(object sender, EventArgs e)
{
    var clientIp = HttpContext.Current.Request.UserHostAddress;
    var cacheKey = $"LoginAttempts_{clientIp}";
    
    // 初始化Redis连接
    var redis = ConnectionMultiplexer.Connect("your-redis-server:6379");
    var db = redis.GetDatabase();

    var attempts = db.StringGet(cacheKey);
    int attemptCount = attempts.HasValue ? int.Parse(attempts) : 0;

    if (attemptCount >= 5)
    {
        lblError.Text = "登录尝试过于频繁,请1分钟后再试。";
        return;
    }

    // 自增计数并设置过期时间
    db.StringIncrement(cacheKey);
    db.KeyExpire(cacheKey, TimeSpan.FromMinutes(1));

    // 原有登录验证逻辑
    // ...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 05:16:40