/// <summary> /// Gets the request identity key. /// </summary> /// <returns>The request identity key.</returns> /// <param name="requestIdentity">Request identity.</param> private string GetRequestIdentityKey(RequestIdentity requestIdentity, CounterRule rule) { var key = $"{requestIdentity.HttpVerb}:{requestIdentity.Path}:{requestIdentity.ClientId}:{rule.Period}"; var idBytes = System.Text.Encoding.UTF8.GetBytes(key); byte[] hashBytes; using (var algorithm = System.Security.Cryptography.SHA1.Create()) { hashBytes = algorithm.ComputeHash(idBytes); } return(BitConverter.ToString(hashBytes).Replace("-", string.Empty)); }
/// <summary> /// Handles the rate limit async. /// </summary> /// <returns>The rate limit async.</returns> /// <param name="httpContext">Http context.</param> /// <param name="requestIdentity">Request identity.</param> private Task <bool> HandleRateLimitAsync(HttpContext httpContext, RequestIdentity requestIdentity) { var limitRules = _options.ClientRules.Where(x => x.ClientId == requestIdentity.ClientId).SelectMany(x => x.CounterRules); var limitRule = limitRules.FirstOrDefault(x => x.EndPoint.Equals(requestIdentity.Path)); if (limitRule != null) { // increment counter var counter = _rateLimiter.Process(requestIdentity, limitRule); // check if limit is reached if (counter.TotalRequests > limitRule.LimitCount) { //will be blocked _logger.LogInformation($"Request {requestIdentity.ClientId},{requestIdentity.HttpVerb},{requestIdentity.Path} has been blocked!"); return(Task.FromResult(true)); } } return(Task.FromResult(false)); }
public RateLimitCounter Process(RequestIdentity requestIdentity, CounterRule rule) { var counter = new RateLimitCounter { Timestamp = DateTime.UtcNow, TotalRequests = 1 }; var counterId = GetRequestIdentityKey(requestIdentity, rule); // serial reads and writes lock (_processLocker) { var entry = _store.Get(counterId); if (entry.HasValue) { // entry has not expired if (entry.Value.Timestamp.AddSeconds(rule.Period) >= DateTime.UtcNow) { // increment request count var totalRequests = entry.Value.TotalRequests + 1; // deep copy counter = new RateLimitCounter { Timestamp = entry.Value.Timestamp, TotalRequests = totalRequests }; } } // stores: id (string) - timestamp (datetime) - total_requests (long) _store.Set(counterId, counter, TimeSpan.FromSeconds(rule.Period)); } return(counter); }