using Newtonsoft.Json.Linq; using Serein.Library.Attributes; using Serein.Library.Network.WebSocketCommunication.Handle; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.WebSockets; using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Serein.Library.Network.WebSocketCommunication { /// /// WebSocket JSON 消息授权管理 /// public class WebSocketAuthorizedHelper { /// /// WebSocket JSON 消息授权管理 /// public WebSocketAuthorizedHelper(string addresPort,string token, Func> inspectionAuthorizedFunc) { this.AddresPort = addresPort; this.TokenKey = token; this.InspectionAuthorizedFunc = inspectionAuthorizedFunc; } /// /// 客户端地址 /// public string AddresPort { get; } /// /// 是否已经鉴权 /// public bool IsAuthorized { get => isAuthorized; } //set => isAuthorized = value; /// /// 是否已经鉴权 /// private bool isAuthorized; /// /// 授权字段 /// private readonly string TokenKey; /// /// 处理消息授权事件 /// private readonly Func> InspectionAuthorizedFunc; private SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1); /// /// 处理消息授权 /// /// public async Task HandleAuthorized(string message) { if(!isAuthorized && semaphoreSlim is null) // 需要重新授权 { semaphoreSlim = new SemaphoreSlim(1); } await semaphoreSlim.WaitAsync(1); if(isAuthorized) // 授权通过,无须再次检查授权 { return; } JObject json = JObject.Parse(message); if(json.TryGetValue(TokenKey,out var token)) { // 交给之前定义的授权方法进行判断 isAuthorized = await InspectionAuthorizedFunc?.Invoke(token); if (isAuthorized) { // 授权通过,释放资源 semaphoreSlim.Release(); semaphoreSlim.Dispose(); semaphoreSlim = null; } } else { isAuthorized = false; } } } /// /// WebSocket服务类 /// [AutoRegister] public class WebSocketServer { /// /// 消息处理 /// public WebSocketMsgHandleHelper MsgHandleHelper { get; } = new WebSocketMsgHandleHelper(); private HttpListener listener; /// /// 创建无须授权验证的WebSocket服务端 /// public WebSocketServer() { this.AuthorizedClients = new ConcurrentDictionary(); this.InspectionAuthorizedFunc = (tokenObj) => Task.FromResult(true); this.IsNeedInspectionAuthorized = false; } /// /// 创建需要授权验证的WebSocket服务端 /// /// token 字段 /// 验证token的方法 public WebSocketServer(string tokenKey, Func> inspectionAuthorizedFunc) { this.TokenKey = tokenKey; this.AuthorizedClients = new ConcurrentDictionary(); this.InspectionAuthorizedFunc = inspectionAuthorizedFunc; this.IsNeedInspectionAuthorized = true; } /// /// 授权 /// public ConcurrentDictionary AuthorizedClients; private readonly string TokenKey; private readonly Func> InspectionAuthorizedFunc; private bool IsNeedInspectionAuthorized = false; /// /// 进行监听服务 /// /// /// public async Task StartAsync(string url) { listener = new HttpListener(); listener.Prefixes.Add(url); await Console.Out.WriteLineAsync($"WebSocket消息处理已启动[{url}]"); try { listener.Start(); } catch (Exception ex) { await Console.Out.WriteLineAsync(ex.Message); return; } while (true) { try { var context = await listener.GetContextAsync(); string clientPoint = context.Request.RemoteEndPoint?.ToString(); await Console.Out.WriteLineAsync($"新的连接加入:{clientPoint}"); if (context.Request.IsWebSocketRequest) { WebSocketAuthorizedHelper authorizedHelper = null; if (IsNeedInspectionAuthorized) { if (AuthorizedClients.TryAdd(clientPoint, new WebSocketAuthorizedHelper(clientPoint, TokenKey, InspectionAuthorizedFunc))) { AuthorizedClients.TryGetValue(clientPoint, out authorizedHelper); } } var webSocketContext = await context.AcceptWebSocketAsync(null); //新连接 _ = HandleWebSocketAsync(webSocketContext.WebSocket, authorizedHelper); // 处理消息 } } catch (Exception ex) { await Console.Out.WriteLineAsync(ex.Message); break; } } } /// /// 停止监听服务 /// public void Stop() { listener?.Stop(); } private async Task HandleWebSocketAsync(WebSocket webSocket, WebSocketAuthorizedHelper authorizedHelper) { // 需要授权,却没有成功创建授权类,关闭连接 if (IsNeedInspectionAuthorized && authorizedHelper is null) { await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); return; } Func SendAsync = async (text) => { await WebSocketServer.SendAsync(webSocket, text); }; var buffer = new byte[1024]; while (webSocket.State == WebSocketState.Open) { var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { SendAsync = null; await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); if (IsNeedInspectionAuthorized) { AuthorizedClients.TryRemove(authorizedHelper.AddresPort, out var _); } } else { var message = Encoding.UTF8.GetString(buffer, 0, result.Count); // 序列为文本 if(!IsNeedInspectionAuthorized) { // 无须授权 _ = MsgHandleHelper.HandleMsgAsync(SendAsync, message); // 处理消息 } else { // 需要授权 if (!authorizedHelper.IsAuthorized) { // 该连接尚未验证授权,尝试检测授权 _ = SendAsync("正在授权"); await authorizedHelper.HandleAuthorized(message); } if (authorizedHelper.IsAuthorized) { // 该连接通过了验证 _ = SendAsync("授权成功"); _ = MsgHandleHelper.HandleMsgAsync(SendAsync, message); // 处理消息 } else { _ = SendAsync("授权失败"); } } } } } /// /// 发送消息 /// /// /// /// public static async Task SendAsync(WebSocket webSocket, string message) { var buffer = Encoding.UTF8.GetBytes(message); await webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, CancellationToken.None); } } }