3

我有一个来自 VS2013 SPA 模板(web api 2.2)的网站,它利用了 ASP.NET Identity 2.1,一切都运行良好。我的控制器方法如下所示:

    [Authorize]
    public Api.Models.Widget Get(int widgetId)
    {
    var requestingUserId = Int32.Parse(Microsoft.AspNet.Identity.IdentityExtensions.GetUserId(User.Identity));
    ...

}

它按预期工作:

  • 未授权用户无权访问
  • 授权用户进入后,我可以获取他们的用户ID

我现在想修改应用程序以防止过多的 API 请求。我计划检查该特定用户 ID 是否在特定时间范围内发出了一定数量的请求。我正在寻找最佳地点的建议。

我不想在每个控制器中重复这个逻辑,看起来动作过滤器可能是最好的地方。但是由于这将需要读取用户 ID,而且我不确定过滤器的顺序是否得到保证,所以如果可能的话,派生已经被调用以进行授权的过滤器并添加我的额外逻辑也可能是有意义的。

我想知道是否有人可以举一个做类似事情的例子?似乎不是“授权”,而是在自定义身份验证过滤器中,我不确定如何将它结合在一起。

感谢您的任何建议...

4

2 回答 2

4

我认为您正在照顾的是一个过滤器,它将限制您的用户提出的请求,因此您应该检查 WebApiThrottle https://github.com/stefanprodan/WebApiThrottle

这应该可以满足您的目标,或者您可以查看源代码以根据您的需要对其进行自定义

于 2014-10-11T22:07:34.870 回答
1

有几个过滤器选项:

授权过滤器 做出关于是否执行操作方法的安全决策,例如执行身份验证或验证请求的属性。

例子:

public class WebApiAuthorizeAttribute : AuthorizeAttribute 
{
    public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        base.OnAuthorization(actionContext);

        Guid userId = new Guid(HttpContext.Current.User.Identity.GetUserId());

        // ...here your validation logic 
    }
}

动作过滤器 包装动作方法执行。这个过滤器可以执行额外的处理,比如提供额外的数据给action方法,检查返回值,或者取消action方法的执行

为了尽量减少对服务器的影响,您可以在用户浏览器中将任何 http get 请求缓存一段预定义的时间,如果用户在该预定义时间内请求相同的 URL,则响应将从浏览器缓存而不是服务器加载。由于 OutputCache 属性不适用于 Web API,您可以在 ASP.NET Web API 帖子中使用此输出缓存作为替代方案,或者您可以为缓存实现自己的操作过滤器属性:

public class CacheFilterAttribute : ActionFilterAttribute
{
    /// <summary>
    /// Gets or sets the cache duration in seconds. The default is 10 seconds.
    /// </summary>
    /// <value>The cache duration in seconds.</value>
    public int Duration
    {
        get;
        set;
    }

    public CacheFilterAttribute()
    {
        Duration = 10;
    }

    public override void OnActionExecuted(FilterExecutedContext filterContext)
    {
        if (Duration <= 0) return;

        HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
        TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);

        cache.SetCacheability(HttpCacheability.Public);
        cache.SetExpires(DateTime.Now.Add(cacheDuration));
        cache.SetMaxAge(cacheDuration);
        cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
    }
}

其他注意事项

一旦用户对您的 web api 进行调用,您必须将 +1 添加到计数器,然后使用此计数器检查同一用户在某个时间范围内的大量调用。这里的问题是在哪里存储这个计数器。

如果您将计数器存储在像 SQL Server 这样的 RDBMS 中,则每个用户调用都将执行一次数据库访问。这可能会成为性能问题。这种存储应尽可能轻。所以使用 NoSQL 数据库可能是一个好方法。

于 2014-10-10T22:16:14.377 回答