try something more for rate limiting

This commit is contained in:
Stanley Dimant
2022-08-03 22:43:00 +02:00
parent aebb7fdbb0
commit 8181018c6d
2 changed files with 68 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ using Microsoft.Extensions.FileProviders;
using Microsoft.AspNetCore.Authorization;
using MareSynchronosServer.Discord;
using AspNetCoreRateLimit;
using MareSynchronosServer.Throttling;
namespace MareSynchronosServer
{
@@ -37,14 +38,6 @@ namespace MareSynchronosServer
{
services.AddHttpContextAccessor();
services.AddSignalR(hubOptions =>
{
hubOptions.MaximumReceiveMessageSize = long.MaxValue;
hubOptions.EnableDetailedErrors = true;
hubOptions.MaximumParallelInvocationsPerClient = 10;
hubOptions.StreamBufferCapacity = 200;
});
services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
@@ -77,6 +70,15 @@ namespace MareSynchronosServer
services.AddAuthorization(options => options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
services.AddSignalR(hubOptions =>
{
hubOptions.MaximumReceiveMessageSize = long.MaxValue;
hubOptions.EnableDetailedErrors = true;
hubOptions.MaximumParallelInvocationsPerClient = 10;
hubOptions.StreamBufferCapacity = 200;
hubOptions.AddFilter<SignalRLimitFilter>();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@@ -0,0 +1,58 @@
using AspNetCoreRateLimit;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
namespace MareSynchronosServer.Throttling;
public class SignalRLimitFilter : IHubFilter
{
private readonly IRateLimitProcessor _processor;
public SignalRLimitFilter(
IOptions<IpRateLimitOptions> options, IProcessingStrategy processing, IRateLimitCounterStore counterStore,
IRateLimitConfiguration rateLimitConfiguration, IIpPolicyStore policyStore)
{
_processor = new IpRateLimitProcessor(options?.Value, policyStore, processing);
}
public async ValueTask<object> InvokeMethodAsync(
HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
{
var httpContext = invocationContext.Context.GetHttpContext();
var ip = httpContext.Connection.RemoteIpAddress.ToString();
var client = new ClientRequestIdentity
{
ClientIp = ip,
Path = invocationContext.HubMethodName,
HttpVerb = "ws",
ClientId = invocationContext.Context.UserIdentifier
};
foreach (var rule in await _processor.GetMatchingRulesAsync(client))
{
var counter = await _processor.ProcessRequestAsync(client, rule);
Console.WriteLine("time: {0}, count: {1}", counter.Timestamp, counter.Count);
if (counter.Count > rule.Limit)
{
var retry = counter.Timestamp.RetryAfterFrom(rule);
throw new HubException($"call limit {retry}");
}
}
Console.WriteLine($"Calling hub method '{invocationContext.HubMethodName}'");
return await next(invocationContext);
}
// Optional method
public Task OnConnectedAsync(HubLifetimeContext context, Func<HubLifetimeContext, Task> next)
{
return next(context);
}
// Optional method
public Task OnDisconnectedAsync(
HubLifetimeContext context, Exception exception, Func<HubLifetimeContext, Exception, Task> next)
{
return next(context, exception);
}
}