使用动作过滤器来限制每个用户对动作的访问次数
本文关键字:用户 访问 过滤器 | 更新日期: 2023-09-27 18:15:30
假设我们有一个动作,我们想要限制每个用户在一段时间内的访问次数,例如用户'A'不能在5分钟内访问样本动作超过10次,我对通过动作过滤器实现它很感兴趣有人知道吗?
您可以编写一个自定义授权过滤器,它将在缓存中存储每个用户对给定操作的调用次数。通过配置缓存过期策略,该值将在过期后自动退出。
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();
}
你可以把"Count"放到一个共享的地方,比如Session。
在OnActionExecuting
中这样做,并且考虑到并发问题,您需要在增加访问计数之前锁定会话,并尽快释放会话。
如果用户'A'满足访问限制,那么你可以通过设置
重定向filterContext.Result = new RedirectToRouteResult("route name", "route parameters")
我最近做了一件事,它限制了用户在给定时间范围内访问url的次数,我采用了将条目粘贴到httpcontext缓存中的方法。
你可以在http://www.jambr.co.uk/Article/action-filter-request-throttle上看到我的博客文章。
这不是你需要的,但可以很容易地修改,而不是在缓存中存储一个空对象,你可以存储你的计数,然后你也可以存储一个滑动过期,而不是一个固定的?有问题就问吧