web socket添加token验证能力(使用token+创建时设置验证回调);flowEnv添加WebSocket处理消息能力,下一步将开发远程登录登录工具。

This commit is contained in:
fengjiayi
2024-10-15 21:56:09 +08:00
parent dbbde4f03e
commit 1d97ea5da1
64 changed files with 811 additions and 395 deletions

View File

@@ -129,7 +129,15 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
foreach ((var model, var method) in methods)
{
Console.WriteLine($"theme value : {model.ThemeValue}");
handlemodule.AddHandleConfigs(model, socketControlBase, method, onExceptionTracking);
try
{
handlemodule.AddHandleConfigs(model, socketControlBase, method, onExceptionTracking);
}
catch (Exception ex)
{
Console.WriteLine($"error in add method: {method.Name}{Environment.NewLine}{ex}");
}
}
}
@@ -147,7 +155,6 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
{
foreach (var module in MyHandleModuleDict.Values)
{
module.HandleSocketMsg(RecoverAsync, json);
}

View File

@@ -1,5 +1,6 @@
using Newtonsoft.Json.Linq;
using Serein.Library.Attributes;
using Serein.Library.Network.WebSocketCommunication.Handle;
using Serein.Library.Web;
using System;
using System.Collections.Concurrent;
@@ -13,35 +14,58 @@ using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication
{
/// <summary>
/// WebSocket客户端
/// </summary>
[AutoRegister]
public class WebSocketClient
{
/// <summary>
/// WebSocket客户端
/// </summary>
public WebSocketClient()
{
}
/// <summary>
/// 消息处理
/// </summary>
public WebSocketMsgHandleHelper MsgHandleHelper { get; } = new WebSocketMsgHandleHelper();
private ClientWebSocket _client = new ClientWebSocket();
/// <summary>
/// 连接到指定WebSocket Server服务
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public async Task ConnectAsync(string uri)
{
await _client.ConnectAsync(new Uri(uri), CancellationToken.None);
await ReceiveAsync();
}
public async Task SendAsync(WebSocket webSocket,string message)
/// <summary>
/// 发送消息
/// </summary>
/// <param name="webSocket"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendAsync(string message)
{
var buffer = Encoding.UTF8.GetBytes(message);
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
await _client.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
/// <summary>
/// 开始处理消息
/// </summary>
/// <returns></returns>
private async Task ReceiveAsync()
{
var buffer = new byte[1024];
while (_client.State == WebSocketState.Open)
{
try
@@ -54,8 +78,7 @@ namespace Serein.Library.Network.WebSocketCommunication
else
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
_ = MsgHandleHelper.HandleMsgAsync(SendAsync, message); // 处理消息
Debug.WriteLine($"Received: {message}");
}
}
@@ -67,9 +90,6 @@ namespace Serein.Library.Network.WebSocketCommunication
}
}
}

View File

@@ -2,6 +2,7 @@
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;
@@ -14,6 +15,84 @@ using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication
{
/// <summary>
/// WebSocket JSON 消息授权管理
/// </summary>
public class WebSocketAuthorizedHelper
{
/// <summary>
/// WebSocket JSON 消息授权管理
/// </summary>
public WebSocketAuthorizedHelper(string addresPort,string token, Func<dynamic, Task<bool>> inspectionAuthorizedFunc)
{
this.AddresPort = addresPort;
this.TokenKey = token;
this.InspectionAuthorizedFunc = inspectionAuthorizedFunc;
}
/// <summary>
/// 客户端地址
/// </summary>
public string AddresPort { get; }
/// <summary>
/// 是否已经鉴权
/// </summary>
public bool IsAuthorized { get => isAuthorized; } //set => isAuthorized = value;
/// <summary>
/// 是否已经鉴权
/// </summary>
private bool isAuthorized;
/// <summary>
/// 授权字段
/// </summary>
private readonly string TokenKey;
/// <summary>
/// 处理消息授权事件
/// </summary>
private readonly Func<dynamic, Task<bool>> InspectionAuthorizedFunc;
private SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
/// <summary>
/// 处理消息授权
/// </summary>
/// <param name="message"></param>
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;
}
}
}
/// <summary>
/// WebSocket服务类
@@ -28,6 +107,36 @@ namespace Serein.Library.Network.WebSocketCommunication
private HttpListener listener;
/// <summary>
/// 创建无须授权验证的WebSocket服务端
/// </summary>
public WebSocketServer()
{
this.AuthorizedClients = new ConcurrentDictionary<string, WebSocketAuthorizedHelper>();
this.InspectionAuthorizedFunc = (tokenObj) => Task.FromResult(true);
this.IsNeedInspectionAuthorized = false;
}
/// <summary>
/// 创建需要授权验证的WebSocket服务端
/// </summary>
/// <param name="tokenKey">token 字段</param>
/// <param name="inspectionAuthorizedFunc">验证token的方法</param>
public WebSocketServer(string tokenKey, Func<dynamic, Task<bool>> inspectionAuthorizedFunc)
{
this.TokenKey = tokenKey;
this.AuthorizedClients = new ConcurrentDictionary<string, WebSocketAuthorizedHelper>();
this.InspectionAuthorizedFunc = inspectionAuthorizedFunc;
this.IsNeedInspectionAuthorized = true;
}
/// <summary>
/// 授权
/// </summary>
public ConcurrentDictionary<string, WebSocketAuthorizedHelper> AuthorizedClients;
private readonly string TokenKey;
private readonly Func<dynamic, Task<bool>> InspectionAuthorizedFunc;
private bool IsNeedInspectionAuthorized = false;
/// <summary>
/// 进行监听服务
/// </summary>
@@ -37,6 +146,7 @@ namespace Serein.Library.Network.WebSocketCommunication
{
listener = new HttpListener();
listener.Prefixes.Add(url);
await Console.Out.WriteLineAsync($"WebSocket消息处理已启动[{url}]");
try
{
listener.Start();
@@ -46,7 +156,6 @@ namespace Serein.Library.Network.WebSocketCommunication
await Console.Out.WriteLineAsync(ex.Message);
return;
}
while (true)
{
@@ -56,11 +165,20 @@ namespace Serein.Library.Network.WebSocketCommunication
string clientPoint = context.Request.RemoteEndPoint?.ToString();
await Console.Out.WriteLineAsync($"新的连接加入:{clientPoint}");
if (context.Request.IsWebSocketRequest)
{
var webSocketContext = await context.AcceptWebSocketAsync(null); //新连接
WebSocketAuthorizedHelper authorizedHelper = null;
if (IsNeedInspectionAuthorized)
{
if (AuthorizedClients.TryAdd(clientPoint, new WebSocketAuthorizedHelper(clientPoint, TokenKey, InspectionAuthorizedFunc)))
{
AuthorizedClients.TryGetValue(clientPoint, out authorizedHelper);
}
}
_ = HandleWebSocketAsync(webSocketContext.WebSocket); // 处理消息
var webSocketContext = await context.AcceptWebSocketAsync(null); //新连接
_ = HandleWebSocketAsync(webSocketContext.WebSocket, authorizedHelper); // 处理消息
}
}
catch (Exception ex)
@@ -79,12 +197,21 @@ namespace Serein.Library.Network.WebSocketCommunication
listener?.Stop();
}
private async Task HandleWebSocketAsync(WebSocket webSocket)
private async Task HandleWebSocketAsync(WebSocket webSocket, WebSocketAuthorizedHelper authorizedHelper)
{
Func<string,Task> SendAsync = async (text) =>
// 需要授权,却没有成功创建授权类,关闭连接
if (IsNeedInspectionAuthorized && authorizedHelper is null)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
return;
}
Func<string, Task> SendAsync = async (text) =>
{
await WebSocketServer.SendAsync(webSocket, text);
};
var buffer = new byte[1024];
while (webSocket.State == WebSocketState.Open)
{
@@ -93,21 +220,45 @@ namespace Serein.Library.Network.WebSocketCommunication
{
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);
_ = MsgHandleHelper.HandleMsgAsync(SendAsync, message);
//foreach (var item in HandldHelpers)
//{
// await item.HandleSocketMsg(webSocket, message);
//}
//Console.WriteLine($"Received: {message}");
//var echoMessage = Encoding.UTF8.GetBytes(message);
//await webSocket.SendAsync(new ArraySegment<byte>(echoMessage, 0, echoMessage.Length), result.MessageType, result.EndOfMessage, CancellationToken.None);
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("授权失败");
}
}
}
}
}