public bool IsWhitelisted(ClientRequestIdentity requestIdentity, RateLimitOptions option)
 {
     if (option.ClientWhitelist.Contains(requestIdentity.ClientId))
     {
         return(true);
     }
     return(false);
 }
예제 #2
0
        private string GetResponseMessage(RateLimitOptions option)
        {
            var message = string.IsNullOrEmpty(option.QuotaExceededMessage)
                ? $"API calls quota exceeded! maximum admitted {option.RateLimitRule.Limit} per {option.RateLimitRule.Period}."
                : option.QuotaExceededMessage;

            return(message);
        }
        public void SaveRateLimitCounter(ClientRequestIdentity requestIdentity, RateLimitOptions option, RateLimitCounter counter, TimeSpan expirationTime)
        {
            var counterId = ComputeCounterKey(requestIdentity, option);
            var rule      = option.RateLimitRule;

            // stores: id (string) - timestamp (datetime) - total_requests (long)
            _counterHandler.Set(counterId, counter, expirationTime);
        }
예제 #4
0
 public IRateManager Create(string name, RateLimitOptions options)
 {
     return(_cache.GetOrAdd(name, key =>
     {
         var store = _serviceProvider.GetRequiredService <IRateStore>();
         IRateManager manager = new RateManager(name, options, store);
         return manager;
     }));
 }
예제 #5
0
 public ClientRateLimitMiddleware(RequestDelegate next,
                                  RateLimitOptions options,
                                  RateLimitProcessor processor
                                  )
 {
     _next      = next;
     _options   = options;
     _processor = processor;
 }
예제 #6
0
        private void GivenTheRloCreatorReturns()
        {
            _rlo1 = new RateLimitOptionsBuilder().Build();
            _rlo2 = new RateLimitOptionsBuilder().WithEnableRateLimiting(true).Build();

            _rloCreator
            .SetupSequence(x => x.Create(It.IsAny <FileRateLimitRule>(), It.IsAny <FileGlobalConfiguration>()))
            .Returns(_rlo1)
            .Returns(_rlo2);
        }
예제 #7
0
 protected RateLimitMiddleware(
     RequestDelegate next,
     RateLimitOptions options,
     TProcessor processor,
     IRateLimitConfiguration config)
 {
     _next      = next;
     _options   = options;
     _processor = processor;
     _config    = config;
 }
 protected RateLimitProcessor(
     RateLimitOptions options,
     IRateLimitCounterStore counterStore,
     ICounterKeyBuilder counterKeyBuilder,
     IRateLimitConfiguration config)
 {
     _options           = options;
     _counterStore      = counterStore;
     _counterKeyBuilder = counterKeyBuilder;
     _config            = config;
 }
예제 #9
0
 protected RateLimitProcessor(
     ICacheManager cacheManager,
     RateLimitOptions options,
     ICounterKeyBuilder counterKeyBuilder,
     IRateLimitConfiguration config)
 {
     _cacheManager      = cacheManager;
     _options           = options;
     _counterKeyBuilder = counterKeyBuilder;
     _config            = config;
 }
예제 #10
0
        public virtual Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLimitOptions option, string retryAfter)
        {
            var message = this.GetResponseMessage(option);

            if (!option.DisableRateLimitHeaders)
            {
                httpContext.Response.Headers["Retry-After"] = retryAfter;
            }

            httpContext.Response.StatusCode = option.HttpStatusCode;
            return(httpContext.Response.WriteAsync(message));
        }
예제 #11
0
        public virtual Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLimitOptions option, string retryAfter)
        {
            var message = string.IsNullOrEmpty(option.QuotaExceededMessage) ? $"API calls quota exceeded! maximum admitted {option.RateLimitRule.Limit} per {option.RateLimitRule.Period}." : option.QuotaExceededMessage;

            if (!option.DisableRateLimitHeaders)
            {
                httpContext.Response.Headers["Retry-After"] = retryAfter;
            }

            httpContext.Response.StatusCode = option.HttpStatusCode;
            return(httpContext.Response.WriteAsync(message));
        }
예제 #12
0
        public static Task <string> ResolveClientAsync(HttpContext httpContext, RateLimitOptions options)
        {
            string clientId    = null;
            string _headerName = options.ClientIdHeader;

            if (httpContext.Request.Headers.TryGetValue(_headerName, out var values))
            {
                clientId = values.First();
            }

            return(Task.FromResult(clientId));
        }
예제 #13
0
 private void ThenTheFollowingIsReturned(RateLimitOptions expected)
 {
     _result.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
     _result.ClientWhitelist.ShouldBe(expected.ClientWhitelist);
     _result.DisableRateLimitHeaders.ShouldBe(expected.DisableRateLimitHeaders);
     _result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
     _result.HttpStatusCode.ShouldBe(expected.HttpStatusCode);
     _result.QuotaExceededMessage.ShouldBe(expected.QuotaExceededMessage);
     _result.RateLimitCounterPrefix.ShouldBe(expected.RateLimitCounterPrefix);
     _result.RateLimitRule.Limit.ShouldBe(expected.RateLimitRule.Limit);
     _result.RateLimitRule.Period.ShouldBe(expected.RateLimitRule.Period);
     TimeSpan.FromSeconds(_result.RateLimitRule.PeriodTimespan).Ticks.ShouldBe(TimeSpan.FromSeconds(expected.RateLimitRule.PeriodTimespan).Ticks);
 }
예제 #14
0
        public RateLimitsViewModel(RateLimitOptions model, INotifiableEventPublisher eventPublisher)
        {
            this.model = model;
            if (this.model.PerUser == null)
            {
                this.model.PerUser = new RateLimitThresholds();
            }

            if (this.model.PerIP == null)
            {
                this.model.PerIP = new RateLimitThresholds();
            }

            eventPublisher.Register(this);
        }
        public string ComputeCounterKey(ClientRequestIdentity requestIdentity, RateLimitOptions option)
        {
            var key = $"{option.RateLimitCounterPrefix}_{requestIdentity.ClientId}_{option.RateLimitRule.Period}_{requestIdentity.HttpVerb}_{requestIdentity.Path}";

            var idBytes = Encoding.UTF8.GetBytes(key);

            byte[] hashBytes;

            using (var algorithm = SHA1.Create())
            {
                hashBytes = algorithm.ComputeHash(idBytes);
            }

            return(BitConverter.ToString(hashBytes).Replace("-", string.Empty));
        }
예제 #16
0
        public virtual ClientRequestIdentity SetIdentity(HttpContext httpContext, RateLimitOptions option)
        {
            var clientId = "client";

            if (httpContext.Request.Headers.Keys.Contains(option.ClientIdHeader))
            {
                clientId = httpContext.Request.Headers[option.ClientIdHeader].First();
            }

            return(new ClientRequestIdentity(
                       clientId,
                       httpContext.Request.Path.ToString().ToLowerInvariant(),
                       httpContext.Request.Method.ToLowerInvariant()
                       ));
        }
예제 #17
0
        private static RateLimitOptions BuildRateLimitOptions(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting)
        {
            RateLimitOptions rateLimitOption = null;

            if (enableRateLimiting)
            {
                rateLimitOption = new RateLimitOptions(enableRateLimiting, globalConfiguration.RateLimitOptions.ClientIdHeader,
                                                       fileReRoute.RateLimitOptions.ClientWhitelist, globalConfiguration.RateLimitOptions.DisableRateLimitHeaders,
                                                       globalConfiguration.RateLimitOptions.QuotaExceededMessage, globalConfiguration.RateLimitOptions.RateLimitCounterPrefix,
                                                       new RateLimitRule(fileReRoute.RateLimitOptions.Period, TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan), fileReRoute.RateLimitOptions.Limit)
                                                       , globalConfiguration.RateLimitOptions.HttpStatusCode);
            }

            return(rateLimitOption);
        }
예제 #18
0
        public RateLimitsViewModel(RateLimitOptions model, INotifyModelChangedEventPublisher eventPublisher, IShellExecuteProvider shellExecuteProvider)
        {
            this.shellExecuteProvider = shellExecuteProvider;
            this.model       = model;
            this.DisplayName = "Rate limits";

            if (this.model.PerUser == null)
            {
                this.model.PerUser = new RateLimitThresholds();
            }

            if (this.model.PerIP == null)
            {
                this.model.PerIP = new RateLimitThresholds();
            }

            eventPublisher.Register(this);
        }
예제 #19
0
        public NetCoreRateLimit(RateLimitType rateLimitType)
        {
            _config = ConfigHelper.GetConfig();

            _cache = new MemoryCache(new MemoryCacheOptions());

            memoryCacheRateLimitCounterStore = new MemoryCacheRateLimitCounterStore(_cache);

            memoryCacheIpPolicyStore = new MemoryCacheIpPolicyStore(_cache, _config.IpRateLimitOptions, _config.IpRateLimitPolicies);
            //添加Policy进内存
            memoryCacheIpPolicyStore.SeedAsync().Wait();

            memoryCacheClientPolicyStore = new MemoryCacheClientPolicyStore(_cache, _config.ClientRateLimitOptions, _config.ClientRateLimitPolicies);
            //添加Policy进内存
            memoryCacheClientPolicyStore.SeedAsync().Wait();

            rateLimitConfiguration = new RateLimitConfiguration(_config.IpRateLimitOptions, _config.ClientRateLimitOptions);



            switch (rateLimitType)
            {
            case RateLimitType.CLIENT_ID:
                _processor = new ClientRateLimitProcessor(_config.ClientRateLimitOptions
                                                          , memoryCacheRateLimitCounterStore, memoryCacheClientPolicyStore, rateLimitConfiguration);
                _options = _config.ClientRateLimitOptions as RateLimitOptions;
                break;

            case RateLimitType.IP:
                _processor = new IpRateLimitProcessor(_config.IpRateLimitOptions
                                                      , memoryCacheRateLimitCounterStore, memoryCacheIpPolicyStore, rateLimitConfiguration);
                _options = _config.IpRateLimitOptions as RateLimitOptions;
                break;

            default:
                _processor = new IpRateLimitProcessor(_config.IpRateLimitOptions
                                                      , memoryCacheRateLimitCounterStore, memoryCacheIpPolicyStore, rateLimitConfiguration);
                _options = _config.IpRateLimitOptions as RateLimitOptions;
                break;
            }
        }
예제 #20
0
        public RateLimitOptions Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration, bool enableRateLimiting)
        {
            RateLimitOptions rateLimitOption = null;

            if (enableRateLimiting)
            {
                rateLimitOption = new RateLimitOptionsBuilder()
                                  .WithClientIdHeader(globalConfiguration.RateLimitOptions.ClientIdHeader)
                                  .WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
                                  .WithDisableRateLimitHeaders(globalConfiguration.RateLimitOptions.DisableRateLimitHeaders)
                                  .WithEnableRateLimiting(fileReRoute.RateLimitOptions.EnableRateLimiting)
                                  .WithHttpStatusCode(globalConfiguration.RateLimitOptions.HttpStatusCode)
                                  .WithQuotaExceededMessage(globalConfiguration.RateLimitOptions.QuotaExceededMessage)
                                  .WithRateLimitCounterPrefix(globalConfiguration.RateLimitOptions.RateLimitCounterPrefix)
                                  .WithRateLimitRule(new RateLimitRule(fileReRoute.RateLimitOptions.Period,
                                                                       TimeSpan.FromSeconds(fileReRoute.RateLimitOptions.PeriodTimespan),
                                                                       fileReRoute.RateLimitOptions.Limit))
                                  .Build();
            }

            return(rateLimitOption);
        }
예제 #21
0
        public override async Task <RateLimitCounter> ProcessRequestAsync(ClientRequestIdentity requestIdentity, RateLimitRule rule, ICounterKeyBuilder counterKeyBuilder, RateLimitOptions rateLimitOptions, CancellationToken cancellationToken = default)
        {
            var counterId = BuildCounterKey(requestIdentity, rule, counterKeyBuilder, rateLimitOptions);

            return(await IncrementAsync(counterId, rule.PeriodTimespan.Value, _config.RateIncrementer));
        }
예제 #22
0
 public RequestLogMiddleware(RequestDelegate next, IOptions <RateLimitOptions> options)
 {
     _next    = next;
     _options = options.Value;
 }
예제 #23
0
 private void WhenICreate()
 {
     _result = _creator.Create(_fileReRoute.RateLimitOptions, _fileGlobalConfig);
 }
예제 #24
0
 private void WithRateLimitOptions(RateLimitOptions expected)
 {
     _result.Data.ReRoute.DownstreamReRoute[0].EnableEndpointEndpointRateLimiting.ShouldBeTrue();
     _result.Data.ReRoute.DownstreamReRoute[0].RateLimitOptions.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
     _result.Data.ReRoute.DownstreamReRoute[0].RateLimitOptions.ClientIdHeader.ShouldBe(expected.ClientIdHeader);
 }
예제 #25
0
 public DownstreamReRouteBuilder WithRateLimitOptions(RateLimitOptions input)
 {
     _rateLimitOptions = input;
     return(this);
 }
예제 #26
0
 public MySqlPolicyStore(RateLimitOptions options, MySqlOptions mySqlOptions)
 {
     _options      = options;
     _mySqlOptions = mySqlOptions;
 }
        public RateLimitHeaders GetRateLimitHeaders(HttpContext context, ClientRequestIdentity requestIdentity, RateLimitOptions option)
        {
            var rule = option.RateLimitRule;
            RateLimitHeaders headers = null;
            var counterId            = ComputeCounterKey(requestIdentity, option);
            var entry = _counterHandler.Get(counterId);

            if (entry.HasValue)
            {
                headers = new RateLimitHeaders(context, rule.Period,
                                               (rule.Limit - entry.Value.TotalRequests).ToString(),
                                               (entry.Value.Timestamp + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo)
                                               );
            }
            else
            {
                headers = new RateLimitHeaders(context,
                                               rule.Period,
                                               rule.Limit.ToString(),
                                               (DateTime.UtcNow + ConvertToTimeSpan(rule.Period)).ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo));
            }

            return(headers);
        }
 private void WhenICreate()
 {
     _result = _creator.Create(_fileReRoute, _fileGlobalConfig, _enabled);
 }
예제 #29
0
 public SqlCacheRateLimiter(IOptionsSnapshot <RateLimitOptions> rateLimits, IDbProvider dbProvider)
 {
     this.rateLimits = rateLimits.Value;
     this.dbProvider = dbProvider;
 }
예제 #30
0
 public RateLimiter(IOptionsSnapshot <RateLimitOptions> rateLimits, IMemoryCache memoryCache)
 {
     this.rateLimits  = rateLimits.Value;
     this.memoryCache = memoryCache;
 }