在ASP.NET MVC中实现请求限制的最佳方法?


212

我们正在尝试各种方法来限制给定时间段内的用户操作:

  • 限制问题/答案帖
  • 限制编辑
  • 限制提要检索

目前,我们正在使用缓存简单地插入用户活动的记录-如果该记录存​​在(如果/当用户进行相同活动时),我们将进行限制。

自动使用缓存可为我们提供陈旧的数据清理和滑动用户活动窗口,但如何扩展可能是个问题。

还有什么其他方式可以确保可以有效地限制请求/用户操作(强调稳定性)?


您是要限制每个用户还是每个问题?如果是每个用户,则可以使用会话,这将是一个较小的集合。
格雷格·奥格尔

1
它是每个用户的,但是我们不能使用Session,因为它需要cookie-我们目前基于IP地址进行限制。
贾罗德·迪克森

1
如今,考虑将nuget软件包github.com/stefanprodan/MvcThrottle用于MVC页面,并将github.com/stefanprodan/WebApiThrottle用于Web api请求
Andy

Answers:


240

这是过去一年中我们在Stack Overflow上一直使用的通用版本:

/// <summary>
/// Decorates any MVC route that needs to have client requests limited by time.
/// </summary>
/// <remarks>
/// Uses the current System.Web.Caching.Cache to store each client request to the decorated route.
/// </remarks>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ThrottleAttribute : ActionFilterAttribute
{
    /// <summary>
    /// A unique name for this Throttle.
    /// </summary>
    /// <remarks>
    /// We'll be inserting a Cache record based on this name and client IP, e.g. "Name-192.168.0.1"
    /// </remarks>
    public string Name { get; set; }

    /// <summary>
    /// The number of seconds clients must wait before executing this decorated route again.
    /// </summary>
    public int Seconds { get; set; }

    /// <summary>
    /// A text message that will be sent to the client upon throttling.  You can include the token {n} to
    /// show this.Seconds in the message, e.g. "Wait {n} seconds before trying again".
    /// </summary>
    public string Message { get; set; }

    public override void OnActionExecuting(ActionExecutingContext c)
    {
        var key = string.Concat(Name, "-", c.HttpContext.Request.UserHostAddress);
        var allowExecute = false;

        if (HttpRuntime.Cache[key] == null)
        {
            HttpRuntime.Cache.Add(key,
                true, // is this the smallest data we can have?
                null, // no dependencies
                DateTime.Now.AddSeconds(Seconds), // absolute expiration
                Cache.NoSlidingExpiration,
                CacheItemPriority.Low,
                null); // no callback

            allowExecute = true;
        }

        if (!allowExecute)
        {
            if (String.IsNullOrEmpty(Message))
                Message = "You may only perform this action every {n} seconds.";

            c.Result = new ContentResult { Content = Message.Replace("{n}", Seconds.ToString()) };
            // see 409 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
            c.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
        }
    }
}

用法示例:

[Throttle(Name="TestThrottle", Message = "You must wait {n} seconds before accessing this url again.", Seconds = 5)]
public ActionResult TestThrottle()
{
    return Content("TestThrottle executed");
}

ASP.NET缓存在这里像冠军一样工作-通过使用它,您可以自动清除油门条目。随着流量的增长,我们看不到这是服务器上的问题。

随时提供有关此方法的反馈;当我们使Stack Overflow更好时,您可以更快地获得Ewok的修复功能:)


5
快速问题-您将c.HttpContext.Request.UserHostAddress值用作键的一部分。该值可能为空或为null还是全部相同?(即,如果您使用的是负载均衡器,并且是该计算机的IP ..而不是真正的客户端)就像代理或负载均衡器(即BIG IP F5)一样,在其中放置相同的数据,您需要检查一下X-Forwarded-For还可以吗?
Pure.Krome

7
@ Pure.Krome-是的,可能是。检索客户端IP时,我们使用辅助函数来检查REMOTE_ADDRHTTP_X_FORWARDED_FOR服务器变量,并进行适当的清理。
Jarrod Dixon

3
@BrettRobi,我很确定他们具有基于用户IP地址的服务器相似性。因此,他们可能仍将使用同一台服务器。
mmcdole 2011年

4
对于那些关心并在评论流中读得很深的人……我们最终编写了自己的重定向,在重定向之前清除了油门缓存键。这样,所有重定向都将通过代码传递以删除密钥,并且它们都不会触发Throttle属性。
SLoret

4
如果你正在寻找的这个网页API的版本,点击这里:stackoverflow.com/questions/20817300/...
爸爸艮

68

Microsoft具有IIS 7的新扩展,称为IIS 7.0的动态IP限制扩展-Beta。

“ IIS 7.0的动态IP限制是一个模块,可提供针对Web服务器和Web站点上的拒绝服务和暴力攻击的防护。通过临时阻止发出并发请求数量异常高的HTTP客户端的IP地址,可以提供这种保护。或在短时间内提出大量要求的人。” http://learn.iis.net/page.aspx/548/using-dynamic-ip-restrictions/

例:

如果将条件设置为“以后阻止”,X requests in Y milliseconds否则X concurrent connections in Y milliseconds将阻止IP地址,Y milliseconds然后将再次允许请求。


1
您知道它是否对Googlebot等抓取工具造成了问题吗?
Helephant 2013年


1
它现已发布并与IIS 8版本捆绑在一起-iis.net/learn/get-started/whats-new-in-iis-8/…–
Matthew

我很乐意使用此功能,但不允许您通过进行限制<location>。这是对应用程序的所有请求,或者没有。
Kasey Speakman

如果您的Web服务器位于负载均衡器后面,则似乎没有用,因为所有流量似乎都来自同一IP地址。除非我缺少明显的东西……
Dscoduc

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.