我有一个来自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是否在某个时间段内发出了一定数量的请求。我正在寻找做这件事的最佳地点的建议
我不想在每个控制器中重复这个逻辑,而且似乎动作过滤器可能是最好的地方。但是,由于这需要读取userid,并且我不确定过滤器的顺序是否得到保证,如果可能的话,派生已经被调用进行授权的过滤器并添加我的额外逻辑也可能是有意义的。
我想知道是否有人能举一个做类似事情的例子?它似乎不是"授权",而是在一个自定义的身份验证过滤器中,我不确定如何将其联系在一起。
谢谢你的建议。。。
我认为您正在关注的是一个过滤器,它将限制用户的请求,因此您应该检查WebApiThrottlehttps://github.com/stefanprodan/WebApiThrottle
这应该是你想要做的事情,或者你可以检查源代码来定制它四个你需要的
有几个过滤器选项:
授权过滤器就是否执行操作方法,例如执行身份验证或验证请求的属性。
示例:
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
}
}
操作筛选器包装操作方法执行。此筛选器可以执行附加处理,例如向操作方法,检查返回值,或取消执行动作方法
为了最大限度地减少对服务器的影响,您可以在用户浏览器中缓存任何http get请求一段预定义的时间,如果用户在该预定义时间内请求相同的URL,则响应将从浏览器缓存而不是服务器加载。由于OutputCache属性不适用于Web API,您可以在ASP.NET Web API文章中使用此输出缓存作为替代,也可以为caching:实现您自己的Action筛选器属性
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中,则每个用户调用都将执行DB访问。这可能会成为性能问题。这个储藏室应该尽可能轻。因此,使用NoSQL数据库可能是一个不错的方法。