假设我们有一个动作,我们希望限制每个用户在一段时间内的访问次数,例如用户'A'在5分钟内无法访问样本动作超过10次,我很有趣通过Action过滤器实现它有没有人知道它?
答案 0 :(得分:4)
您可以编写自定义授权过滤器,该过滤器将存储每个用户在缓存中的给定操作的调用次数。通过配置缓存过期策略,该值将在该期限到期后自动逐出。
public class AuthorizeWithThrottleAttribute : AuthorizeAttribute
{
private class Attempts
{
public int NumberOfAccess { get; set; }
}
public int Seconds { get; private set; }
public int Count { get; private set; }
public AuthorizeWithThrottleAttribute(int seconds, int count)
{
Seconds = seconds;
Count = count;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
return false;
}
var rd = httpContext.Request.RequestContext.RouteData;
var action = rd.GetRequiredString("action");
var controller = rd.GetRequiredString("controller");
// Remark: if you are using areas maybe you could also want
// to constrain the key per area
var key = string.Format("throttle-{0}-{1}-{2}", httpContext.User.Identity.Name, controller, action);
var policy = new CacheItemPolicy
{
AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(Seconds),
};
// Here we are using the new caching API introduced in .NET 4.0:
// http://msdn.microsoft.com/en-us/library/system.runtime.caching.aspx
// If you are using an older version of the framework you could use
// the legacy HttpContext.Cache instead which offers the same expiration
// policy features as the new
var attempts = MemoryCache.Default.Get(key) as Attempts;
if (attempts == null)
{
attempts = new Attempts();
MemoryCache.Default.Set(key, attempts, policy);
}
if (attempts.NumberOfAccess < Count)
{
attempts.NumberOfAccess++;
return true;
}
httpContext.Items["throttled"] = true;
return false;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var throttled = filterContext.HttpContext.Items["throttled"];
if (throttled != null && (bool)throttled)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
filterContext.Result = new ContentResult
{
Content = string.Format("You may only call this action {0} times every {1} seconds", Count, Seconds),
ContentType = "text/plain"
};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
然后装饰:
[AuthorizeWithThrottle(10, 5)]
public ActionResult Foo()
{
return View();
}
答案 1 :(得分:0)
您可以将“计数”放入共享位置,例如会话。
在OnActionExecuting
中执行此操作,并考虑并发问题,您需要在阻止访问计数之前锁定会话,并尽快释放它。
如果用户'A'符合访问限制,则可以通过设置
进行重定向filterContext.Result = new RedirectToRouteResult("route name", "route parameters")
答案 2 :(得分:0)
我最近做了一些事情,限制了用户在给定时间范围内访问网址的次数,我采取了将该项目粘贴到httpcontext缓存中的方法。
您可以在http://www.jambr.co.uk/Article/action-filter-request-throttle
上看到我的博文这不是您需要的,但可以轻松修改,而不是在缓存中存储空对象,您可以存储您的计数,然后您还可以存储滑动到期而不是固定的?有问题请问。