public async Task <RateLimitingValidationResponse> ValidateContext(RateLimitingValidationContext rateLimitingValidationContext)
        {
            var rateLimitingCounter = new RateLimitingCounter
            {
                Timestamp = DateTime.UtcNow,
                Count     = 1
            };
            var expirationTime = rateLimitingValidationContext.Period.ToTimeSpan();

            var counterKey = await _rateLimitingCounterKeyBuilder.BuildCounterKey(rateLimitingValidationContext);

            var rateLimitingCounterEntry = await _rateLimitingCounterStore.GetCounter(counterKey);

            if (rateLimitingCounterEntry != null)
            {
                rateLimitingCounter        = rateLimitingCounterEntry;
                rateLimitingCounter.Count += 1;
                var expirationDateTime = rateLimitingCounterEntry.Timestamp + rateLimitingValidationContext.Period.ToTimeSpan();
                expirationTime = expirationDateTime - DateTime.UtcNow;
            }
            await _rateLimitingCounterStore.SetCounter(counterKey, rateLimitingCounterEntry, expirationTime);

            var rateLimitingValidationResponse = new RateLimitingValidationResponse
            {
                RateLimitingValidationContext = rateLimitingValidationContext,
                RateLimitingCounter           = rateLimitingCounter
            };

            return(rateLimitingValidationResponse);
        }
        public Task <string> BuildCounterKey(RateLimitingValidationContext rateLimitingValidationContext)
        {
            var counterKeyTemplate = $"{rateLimitingValidationContext.TrafficInitiatorId}_{rateLimitingValidationContext.Path}" +
                                     $"{rateLimitingValidationContext.Method}_{rateLimitingValidationContext.Limit}" +
                                     $"{rateLimitingValidationContext.Period}";
            var counterKeyBytes = Encoding.UTF8.GetBytes(counterKeyTemplate);

            using var hashingAlgorithm = SHA1.Create();
            var counterKeyHashBytes = hashingAlgorithm.ComputeHash(counterKeyBytes);
            var counterKey          = BitConverter.ToString(counterKeyHashBytes)
                                      .Replace("-", string.Empty);

            return(Task.FromResult(counterKey));
        }
Exemple #3
0
        public async Task Invoke(ITrafficContext trafficContext, BrolicTrafficDelegate next)
        {
            var trafficInitiatorId = await _trafficInitiatorIdentifier.IdentifyTrafficInitiator(trafficContext);

            var httpContext = trafficContext.HttpContext;
            var httpMethod  = httpContext.Request.Method;
            var rateLimitingRouteOptions    = trafficContext.Route.GetRateLimitingRouteOptions();
            var applicableRateLimitingRules = rateLimitingRouteOptions.Rules
                                              .Where(r => !r.Methods.Any() || r.Methods.Contains(httpMethod));

            var rateLimitingValidationResponses = new List <RateLimitingValidationResponse>();

            foreach (var applicableRateLimitingRule in applicableRateLimitingRules)
            {
                var path         = httpContext.Request.Path;
                var parsedMethod = !applicableRateLimitingRule.Methods.Any()
                    ? "Any"
                    : applicableRateLimitingRule.Methods.Aggregate(string.Empty, (current, method) =>
                {
                    current += method;
                    return(current);
                });

                var rateLimitingValidationContext = new RateLimitingValidationContext
                {
                    TrafficInitiatorId = trafficInitiatorId,
                    Path   = path,
                    Method = parsedMethod,
                    Limit  = applicableRateLimitingRule.Limit,
                    Period = applicableRateLimitingRule.Period
                };
                var rateLimitingValidationResponse = await _rateLimitingValidationStrategy.ValidateContext(rateLimitingValidationContext);

                rateLimitingValidationResponses.Add(rateLimitingValidationResponse);
            }

            if (rateLimitingValidationResponses.Any(r => !r.IsValid))
            {
                httpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
                return;
            }

            await next(trafficContext);
        }