try something more for rate limiting
This commit is contained in:
		| @@ -18,6 +18,7 @@ using Microsoft.Extensions.FileProviders; | |||||||
| using Microsoft.AspNetCore.Authorization; | using Microsoft.AspNetCore.Authorization; | ||||||
| using MareSynchronosServer.Discord; | using MareSynchronosServer.Discord; | ||||||
| using AspNetCoreRateLimit; | using AspNetCoreRateLimit; | ||||||
|  | using MareSynchronosServer.Throttling; | ||||||
|  |  | ||||||
| namespace MareSynchronosServer | namespace MareSynchronosServer | ||||||
| { | { | ||||||
| @@ -37,14 +38,6 @@ namespace MareSynchronosServer | |||||||
|         { |         { | ||||||
|             services.AddHttpContextAccessor(); |             services.AddHttpContextAccessor(); | ||||||
|  |  | ||||||
|             services.AddSignalR(hubOptions => |  | ||||||
|             { |  | ||||||
|                 hubOptions.MaximumReceiveMessageSize = long.MaxValue; |  | ||||||
|                 hubOptions.EnableDetailedErrors = true; |  | ||||||
|                 hubOptions.MaximumParallelInvocationsPerClient = 10; |  | ||||||
|                 hubOptions.StreamBufferCapacity = 200; |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             services.AddMemoryCache(); |             services.AddMemoryCache(); | ||||||
|  |  | ||||||
|             services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")); |             services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")); | ||||||
| @@ -77,6 +70,15 @@ namespace MareSynchronosServer | |||||||
|             services.AddAuthorization(options => options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); |             services.AddAuthorization(options => options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()); | ||||||
|  |  | ||||||
|             services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>(); |             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. |         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | ||||||
|   | |||||||
| @@ -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); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Stanley Dimant
					Stanley Dimant