@@ -23,6 +23,7 @@ public class WebSocketHandler : IDisposable
2323 private readonly SemaphoreSlim _broadcastLock = new SemaphoreSlim ( 1 , 1 ) ;
2424 private readonly CancellationTokenSource _cts = new CancellationTokenSource ( ) ;
2525 private readonly int _maxConnections ;
26+ private readonly string ? _apiKey ;
2627 private readonly Task _pingTask ;
2728 private bool _disposed ;
2829 private WebSocketCommandHandler ? _commandHandler ;
@@ -31,9 +32,10 @@ public class WebSocketHandler : IDisposable
3132
3233 public event Action ? ConnectionCountChanged ;
3334
34- public WebSocketHandler ( int maxConnections = 100 )
35+ public WebSocketHandler ( int maxConnections = 100 , string ? apiKey = null )
3536 {
3637 _maxConnections = maxConnections < 10 ? 10 : maxConnections ;
38+ _apiKey = apiKey ;
3739 _pingTask = PingLoop ( ) ;
3840 }
3941
@@ -103,14 +105,15 @@ public async Task HandleConnection(HttpListenerContext context)
103105 return ;
104106 }
105107
108+ if ( ! ValidateApiKey ( context . Request ) )
109+ {
110+ await WriteJsonError ( context . Response , 401 , ErrorCode . Unauthorized , LangManager . Get ( "Api_InvalidApiKey" ) ) ;
111+ return ;
112+ }
113+
106114 if ( _connections . Count >= _maxConnections )
107115 {
108- context . Response . StatusCode = 429 ;
109- var bytes = Encoding . UTF8 . GetBytes ( "{\" success\" :false,\" errorInfo\" :{\" code\" :\" TooManyConnections\" ,\" message\" :\" " + LangManager . Get ( "Ws_ConnectionLimit" ) + "\" }}" ) ;
110- context . Response . ContentType = "application/json" ;
111- context . Response . ContentLength64 = bytes . Length ;
112- await context . Response . OutputStream . WriteAsync ( bytes , 0 , bytes . Length ) ;
113- context . Response . Close ( ) ;
116+ await WriteJsonError ( context . Response , 429 , "TooManyConnections" , LangManager . Get ( "Ws_ConnectionLimit" ) ) ;
114117 return ;
115118 }
116119
@@ -215,6 +218,32 @@ private static async Task SendErrorQuietly(WebSocket ws, string code, string err
215218 }
216219 }
217220
221+ private bool ValidateApiKey ( HttpListenerRequest request )
222+ {
223+ return ValidateApiKeyCore ( _apiKey , request . QueryString [ "apiKey" ] , request . Headers [ "X-API-Key" ] ) ;
224+ }
225+
226+ internal static bool ValidateApiKeyCore ( string ? configuredKey , string ? queryApiKey , string ? headerApiKey )
227+ {
228+ return Router . ValidateApiKeyCore ( configuredKey , queryApiKey )
229+ || Router . ValidateApiKeyCore ( configuredKey , headerApiKey ) ;
230+ }
231+
232+ private static async Task WriteJsonError ( HttpListenerResponse response , int statusCode , string code , string message )
233+ {
234+ var json = JsonConvert . SerializeObject ( new
235+ {
236+ success = false ,
237+ errorInfo = new { code , message }
238+ } ) ;
239+ var bytes = Encoding . UTF8 . GetBytes ( json ) ;
240+ response . StatusCode = statusCode ;
241+ response . ContentType = "application/json" ;
242+ response . ContentLength64 = bytes . Length ;
243+ await response . OutputStream . WriteAsync ( bytes , 0 , bytes . Length ) ;
244+ response . Close ( ) ;
245+ }
246+
218247 public async Task Broadcast ( string message )
219248 {
220249 var bytes = Encoding . UTF8 . GetBytes ( message ) ;
0 commit comments