如何在Web Api中限制请求?

60

我正在尝试通过以下方式实现请求限制:

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

我已将该代码导入我的解决方案,并使用属性修饰了API控制器端点:

[Route("api/dothis/{id}")]
[AcceptVerbs("POST")]
[Throttle(Name = "TestThrottle", Message = "You must wait {n} seconds before accessing this url again.", Seconds = 5)]
[Authorize]
public HttpResponseMessage DoThis(int id) {...}

这段代码可以编译通过,但属性的代码没有被执行,并且限流也没有生效。虽然我没有收到任何错误提示,但是我错过了什么吗?

11个回答

0
在访问 Web API 需要授权的场景中,使用 ActionFilterAttribute 的建议实际上不会限制客户端访问未被授权的 API。客户端可以继续调用 API 而没有任何限制。
WebApiThrottling 项目使用 DelegatingHandler 来解决这个问题。以下是一个示例 DelegatingHandler,它基本上做了与其他使用 ActionFilterAttribute 的答案相同的事情。添加的好处是它适用于已经授权和未经授权的客户端。
public enum TimeUnit
{
    Minute = 60,
    Hour = 3600,
    Day = 86400
}

public class ThrottleHandler : DelegatingHandler
{
    private class Error
    {
        public string Message;
    }

    private TimeUnit _timeUnit;
    private int _count;

    public ThrottleHandler(TimeUnit unit, int count)
    {
        _timeUnit = unit;
        _count = count;
    }

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var seconds = Convert.ToInt32(TimeUnit);

        var key = string.Join(
            "-",
            seconds,
            request.Method,
            request.RequestUri.AbsolutePath,
            GetClientIpAddress(request)
        );

        // increment the cache value
        var cnt = 1;
        if (HttpRuntime.Cache[key] != null)
        {
            cnt = (int)HttpRuntime.Cache[key] + 1;
        }

        HttpRuntime.Cache.Insert(
            key,
            cnt,
            null,
            DateTime.UtcNow.AddSeconds(seconds),
            Cache.NoSlidingExpiration,
            CacheItemPriority.Low,
            null
        );

        if (cnt > _count)
        {
            // break out of execution
            var response = request.CreateResponse((HttpStatusCode)429, new Error() { Message = "API call quota exceeded! {Count} calls per {TimeUnit} allowed." });
            return Task.FromResult(response);
        }

        return base.SendAsync(request, cancellationToken);
    }

    private string GetClientIpAddress(HttpRequestMessage request)
    {
        if (request.Properties.ContainsKey("MS_HttpContext"))
        {
            return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
        }

        if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
        {
            RemoteEndpointMessageProperty prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
            return prop.Address;
        }

        if (HttpContext.Current != null)
        {
            return HttpContext.Current.Request.UserHostAddress;
        }

        return String.Empty;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接