mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 02:42:52 +08:00
Make rate-limiting client whitelist dynamic
* Refactor `RateLimitOptions.ClientWhiteList` * Fix typo in variable `enbleRateLimiting` * Fix case in variable `clientIdheader` author Taiwo Otubamowo <totubamowo@deloitte.co.uk>
This commit is contained in:
parent
fbd9c01a42
commit
21be46e680
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ocelot.Configuration.Builder
|
namespace Ocelot.Configuration.Builder
|
||||||
{
|
{
|
||||||
@ -7,6 +8,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
private bool _enableRateLimiting;
|
private bool _enableRateLimiting;
|
||||||
private string _clientIdHeader;
|
private string _clientIdHeader;
|
||||||
private List<string> _clientWhitelist;
|
private List<string> _clientWhitelist;
|
||||||
|
private Func<List<string>> _getClientWhitelist;
|
||||||
private bool _disableRateLimitHeaders;
|
private bool _disableRateLimitHeaders;
|
||||||
private string _quotaExceededMessage;
|
private string _quotaExceededMessage;
|
||||||
private string _rateLimitCounterPrefix;
|
private string _rateLimitCounterPrefix;
|
||||||
@ -19,15 +21,15 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RateLimitOptionsBuilder WithClientIdHeader(string clientIdheader)
|
public RateLimitOptionsBuilder WithClientIdHeader(string clientIdHeader)
|
||||||
{
|
{
|
||||||
_clientIdHeader = clientIdheader;
|
_clientIdHeader = clientIdHeader;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RateLimitOptionsBuilder WithClientWhiteList(List<string> clientWhitelist)
|
public RateLimitOptionsBuilder WithClientWhiteList(Func<List<string>> getClientWhitelist)
|
||||||
{
|
{
|
||||||
_clientWhitelist = clientWhitelist;
|
_getClientWhitelist = getClientWhitelist;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,9 +65,9 @@ namespace Ocelot.Configuration.Builder
|
|||||||
|
|
||||||
public RateLimitOptions Build()
|
public RateLimitOptions Build()
|
||||||
{
|
{
|
||||||
return new RateLimitOptions(_enableRateLimiting, _clientIdHeader, _clientWhitelist,
|
return new RateLimitOptions(_enableRateLimiting, _clientIdHeader, _getClientWhitelist,
|
||||||
_disableRateLimitHeaders, _quotaExceededMessage, _rateLimitCounterPrefix,
|
_disableRateLimitHeaders, _quotaExceededMessage, _rateLimitCounterPrefix,
|
||||||
_rateLimitRule, _httpStatusCode);
|
_rateLimitRule, _httpStatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
{
|
{
|
||||||
return new RateLimitOptionsBuilder()
|
return new RateLimitOptionsBuilder()
|
||||||
.WithClientIdHeader(globalConfiguration.RateLimitOptions.ClientIdHeader)
|
.WithClientIdHeader(globalConfiguration.RateLimitOptions.ClientIdHeader)
|
||||||
.WithClientWhiteList(fileRateLimitRule.ClientWhitelist)
|
.WithClientWhiteList(() => fileRateLimitRule.ClientWhitelist)
|
||||||
.WithDisableRateLimitHeaders(globalConfiguration.RateLimitOptions.DisableRateLimitHeaders)
|
.WithDisableRateLimitHeaders(globalConfiguration.RateLimitOptions.DisableRateLimitHeaders)
|
||||||
.WithEnableRateLimiting(fileRateLimitRule.EnableRateLimiting)
|
.WithEnableRateLimiting(fileRateLimitRule.EnableRateLimiting)
|
||||||
.WithHttpStatusCode(globalConfiguration.RateLimitOptions.HttpStatusCode)
|
.WithHttpStatusCode(globalConfiguration.RateLimitOptions.HttpStatusCode)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ocelot.Configuration
|
namespace Ocelot.Configuration
|
||||||
{
|
{
|
||||||
@ -7,12 +8,14 @@ namespace Ocelot.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RateLimitOptions
|
public class RateLimitOptions
|
||||||
{
|
{
|
||||||
public RateLimitOptions(bool enbleRateLimiting, string clientIdHeader, List<string> clientWhitelist, bool disableRateLimitHeaders,
|
private readonly Func<List<string>> _getClientWhitelist;
|
||||||
|
|
||||||
|
public RateLimitOptions(bool enableRateLimiting, string clientIdHeader, Func<List<string>> getClientWhitelist, bool disableRateLimitHeaders,
|
||||||
string quotaExceededMessage, string rateLimitCounterPrefix, RateLimitRule rateLimitRule, int httpStatusCode)
|
string quotaExceededMessage, string rateLimitCounterPrefix, RateLimitRule rateLimitRule, int httpStatusCode)
|
||||||
{
|
{
|
||||||
EnableRateLimiting = enbleRateLimiting;
|
EnableRateLimiting = enableRateLimiting;
|
||||||
ClientIdHeader = clientIdHeader;
|
ClientIdHeader = clientIdHeader;
|
||||||
ClientWhitelist = clientWhitelist ?? new List<string>();
|
_getClientWhitelist = getClientWhitelist;
|
||||||
DisableRateLimitHeaders = disableRateLimitHeaders;
|
DisableRateLimitHeaders = disableRateLimitHeaders;
|
||||||
QuotaExceededMessage = quotaExceededMessage;
|
QuotaExceededMessage = quotaExceededMessage;
|
||||||
RateLimitCounterPrefix = rateLimitCounterPrefix;
|
RateLimitCounterPrefix = rateLimitCounterPrefix;
|
||||||
@ -22,18 +25,21 @@ namespace Ocelot.Configuration
|
|||||||
|
|
||||||
public RateLimitRule RateLimitRule { get; private set; }
|
public RateLimitRule RateLimitRule { get; private set; }
|
||||||
|
|
||||||
public List<string> ClientWhitelist { get; private set; }
|
/// <summary>
|
||||||
|
/// Gets the list of white listed clients
|
||||||
|
/// </summary>
|
||||||
|
public List<string> ClientWhitelist { get => _getClientWhitelist(); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the HTTP header that holds the client identifier, by default is X-ClientId
|
/// Gets or sets the HTTP header that holds the client identifier, by default is X-ClientId
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ClientIdHeader { get; private set; }
|
public string ClientIdHeader { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is set to 429 (Too Many Requests)
|
/// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is set to 429 (Too Many Requests)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int HttpStatusCode { get; private set; }
|
public int HttpStatusCode { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message.
|
/// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message.
|
||||||
/// If none specified the default will be:
|
/// If none specified the default will be:
|
||||||
@ -44,8 +50,8 @@ namespace Ocelot.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the counter prefix, used to compose the rate limit counter cache key
|
/// Gets or sets the counter prefix, used to compose the rate limit counter cache key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RateLimitCounterPrefix { get; private set; }
|
public string RateLimitCounterPrefix { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables endpoint rate limiting based URL path and HTTP verb
|
/// Enables endpoint rate limiting based URL path and HTTP verb
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -56,4 +62,4 @@ namespace Ocelot.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DisableRateLimitHeaders { get; private set; }
|
public bool DisableRateLimitHeaders { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
};
|
};
|
||||||
var expected = new RateLimitOptionsBuilder()
|
var expected = new RateLimitOptionsBuilder()
|
||||||
.WithClientIdHeader("ClientIdHeader")
|
.WithClientIdHeader("ClientIdHeader")
|
||||||
.WithClientWhiteList(fileReRoute.RateLimitOptions.ClientWhitelist)
|
.WithClientWhiteList(() => fileReRoute.RateLimitOptions.ClientWhitelist)
|
||||||
.WithDisableRateLimitHeaders(true)
|
.WithDisableRateLimitHeaders(true)
|
||||||
.WithEnableRateLimiting(true)
|
.WithEnableRateLimiting(true)
|
||||||
.WithHttpStatusCode(200)
|
.WithHttpStatusCode(200)
|
||||||
|
@ -49,15 +49,15 @@ namespace Ocelot.UnitTests.RateLimit
|
|||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_call_middleware_and_ratelimiting()
|
public void should_call_middleware_and_ratelimiting()
|
||||||
{
|
{
|
||||||
var upstreamTemplate = new UpstreamPathTemplateBuilder().Build();
|
var upstreamTemplate = new UpstreamPathTemplateBuilder().Build();
|
||||||
|
|
||||||
var downstreamReRoute = new DownstreamReRouteBuilder()
|
var downstreamReRoute = new DownstreamReRouteBuilder()
|
||||||
.WithEnableRateLimiting(true)
|
.WithEnableRateLimiting(true)
|
||||||
.WithRateLimitOptions(new RateLimitOptions(true, "ClientId", new List<string>(), false, "", "", new RateLimitRule("1s", 100, 3), 429))
|
.WithRateLimitOptions(new RateLimitOptions(true, "ClientId", () => new List<string>(), false, "", "", new RateLimitRule("1s", 100, 3), 429))
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.WithUpstreamPathTemplate(upstreamTemplate)
|
.WithUpstreamPathTemplate(upstreamTemplate)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var reRoute = new ReRouteBuilder()
|
var reRoute = new ReRouteBuilder()
|
||||||
.WithDownstreamReRoute(downstreamReRoute)
|
.WithDownstreamReRoute(downstreamReRoute)
|
||||||
@ -82,7 +82,7 @@ namespace Ocelot.UnitTests.RateLimit
|
|||||||
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
|
.WithDownstreamReRoute(new DownstreamReRouteBuilder()
|
||||||
.WithEnableRateLimiting(true)
|
.WithEnableRateLimiting(true)
|
||||||
.WithRateLimitOptions(
|
.WithRateLimitOptions(
|
||||||
new Ocelot.Configuration.RateLimitOptions(true, "ClientId", new List<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429))
|
new Ocelot.Configuration.RateLimitOptions(true, "ClientId", () => new List<string>() { "ocelotclient2" }, false, "", "", new RateLimitRule("1s", 100, 3), 429))
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build())
|
.Build())
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
@ -102,8 +102,8 @@ namespace Ocelot.UnitTests.RateLimit
|
|||||||
|
|
||||||
private void WhenICallTheMiddlewareMultipleTime(int times)
|
private void WhenICallTheMiddlewareMultipleTime(int times)
|
||||||
{
|
{
|
||||||
var clientId = "ocelotclient1";
|
var clientId = "ocelotclient1";
|
||||||
|
|
||||||
for (int i = 0; i < times; i++)
|
for (int i = 0; i < times; i++)
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
|
var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
|
||||||
@ -117,8 +117,8 @@ namespace Ocelot.UnitTests.RateLimit
|
|||||||
|
|
||||||
private void WhenICallTheMiddlewareWithWhiteClient()
|
private void WhenICallTheMiddlewareWithWhiteClient()
|
||||||
{
|
{
|
||||||
var clientId = "ocelotclient2";
|
var clientId = "ocelotclient2";
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
|
var request = new HttpRequestMessage(new HttpMethod("GET"), _url);
|
||||||
@ -127,10 +127,10 @@ namespace Ocelot.UnitTests.RateLimit
|
|||||||
_downstreamContext.HttpContext.Request.Headers.TryAdd("ClientId", clientId);
|
_downstreamContext.HttpContext.Request.Headers.TryAdd("ClientId", clientId);
|
||||||
|
|
||||||
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
_middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
|
||||||
_responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode;
|
_responseStatusCode = (int)_downstreamContext.HttpContext.Response.StatusCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenresponseStatusCodeIs429()
|
private void ThenresponseStatusCodeIs429()
|
||||||
{
|
{
|
||||||
_responseStatusCode.ShouldBe(429);
|
_responseStatusCode.ShouldBe(429);
|
||||||
@ -145,7 +145,7 @@ namespace Ocelot.UnitTests.RateLimit
|
|||||||
internal class FakeStream : Stream
|
internal class FakeStream : Stream
|
||||||
{
|
{
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
{
|
{
|
||||||
//do nothing
|
//do nothing
|
||||||
//throw new System.NotImplementedException();
|
//throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
@ -176,4 +176,4 @@ namespace Ocelot.UnitTests.RateLimit
|
|||||||
public override long Length { get; }
|
public override long Length { get; }
|
||||||
public override long Position { get; set; }
|
public override long Position { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user