首页
视频
资源
登录
原
.net6 Signalr+Vue3 的运用(下)
2781
人阅读
2023/2/1 17:29
总访问:
2615440
评论:
0
收藏:
0
手机
分类:
.net后台框架
![.netcore](https://img.tnblog.net/arcimg/hb/c857299a86d84ee7b26d181a31e58234.jpg ".netcore") >#.net6 Signalr+Vue3 的运用(下) [TOC] tn2>上篇链接:https://www.tnblog.net/hb/article/details/7961 SignalR 中的用户 ------------ tn>SignalR 中的单个用户可以与一个应用建立多个连接。 举例:当你手机和电脑连接到SignalR时,识别到当前用户多个设备可以同时发送消息。 可以通过中心内的`Context.UserIdentifier`属性访问连接的用户标识符。 ### 示例 tn2>接下来我们结合上篇,在`ClientHubController`控制器的基础上,添加一个`SendCustomUserMessage2`接口专门对单一用户关联的所有设备发送消息。 ```csharp /// <summary> /// 发送指定消息给指定的用户 /// </summary> /// <param name="userid"></param> /// <param name="date"></param> /// <param name="hubContext"></param> /// <returns></returns> [HttpGet("SendCustomUserMessage2", Name = "SendCustomUserMessage2")] public async Task<IActionResult> SendCustomUserMessage2( string username, string date, [FromServices] IHubContext<ChatHub, IChatClient> hubContext ) { await hubContext.Clients.User(username).SendCustomUserMessage(date); return Ok("Send Successful!"); } ``` tn2>测试两个页面登录同一个`bob`用户,然后在服务器端swagger调用方法,两个页面将同时收到消息。 ![](https://img.tnblog.net/arcimg/hb/62a605b59b3a4bb6b28107ff3573747b.png) ![](https://img.tnblog.net/arcimg/hb/c14b2d679dcb491bb333397d12874750.png) tn2>那么有人要问了能不能不以`UserIdentifier`作为标识换成其他标识,比如通过邮箱来进行标识? 可以进行改变授权的逻辑吗? 当然可以。 ### 自定义设备标识 tn>可以通过实现`IUserIdProvider`接口中的`GetUserId`方法,来进行设备的区分,我这里通过邮箱的方式来作为我们区分的标识。 tn2>首先我们在后端定义`EmailBasedUserIdProvider`类实现`IUserIdProvider`接口,然后我们再对其重新进行依赖注入。 ```csharp public class EmailBasedUserIdProvider : IUserIdProvider { public string? GetUserId(HubConnectionContext connection) { return connection.User?.FindFirst(ClaimTypes.Email)?.Value; } } ``` ```csharp builder.Services.AddSingleton<IUserIdProvider, EmailBasedUserIdProvider>(); ``` tn2>然后我们在`MyJWTBearer`中添加一个`Email`的Claim参数。 ```csharp var claims = new[] { new Claim(ClaimTypes.NameIdentifier, httpContext.Request.Query["user"]), new Claim(ClaimTypes.Email, $"{httpContext.Request.Query["user"]}@tnblog.com"), }; ``` tn2>这样就可以了,测试一下。 ![](https://img.tnblog.net/arcimg/hb/b67950219e3f47549547e0f63ba5a28a.png) ![](https://img.tnblog.net/arcimg/hb/f794e88f51f74ff7afcea0d3becaebb3.png) ### 自定义授权逻辑 tn2>接下来我们通过定义`TnblogRequirement `实现自定义授权,然后添加一下自定义授权策略一下,并在`SendMessage`方法上添加自定义授权。 ```csharp public class TnblogRequirement : AuthorizationHandler<TnblogRequirement, HubInvocationContext>, IAuthorizationRequirement { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TnblogRequirement requirement, HubInvocationContext resource) { // 首先用户的授权Identity 属性不能为空 // 然后我们禁用cc@tnblog.com邮箱的账户 if ( context.User.Identity != null && (context.User?.FindFirst(ClaimTypes.Email).Value != "cc@tnblog.com") ) { context.Succeed(requirement); } else { context.Fail(new AuthorizationFailureReason(requirement, "授权失败")); } return Task.CompletedTask; } } ``` ```csharp builder.Services.AddAuthorization(options => { options.AddPolicy("Tnblog", policy => { policy.Requirements.Add(new TnblogRequirement()); }); }); ``` ```csharp [Authorize("Tnblog")] public async Task SendMessage(string data) { Console.WriteLine("Have one Data!"); await Clients.All.SendAll(_common.SendAll(data)); await Clients.Caller.SendAll(_common.SendCaller()); } ``` tn2>接下来我们分别用bob账户和cc账户来进行检测,发现cc账户发送消息失败。 ![](https://img.tnblog.net/arcimg/hb/2dd47717fa934f4eb3cdce1bf9fde080.png) SignalR 中的组 ------------ tn2>简单来讲,按照客户端连接来进行分组。 在`ChatHub`中,我们可以直接使用`Group`来进行组的添加和删除,由于它的Groups是不允许外部查看访问的所以我这里自定义的一个类来专门记录。 ```csharp public static class GroupStore { public static Dictionary<string, List<string>> Groups = new Dictionary<string, List<string>>(); public static void Add(string groupname,string Id) { if (Groups.ContainsKey(groupname)) { if (Groups.TryGetValue(groupname,out var values)) { if (values.Contains(Id)) return; values.Add(Id); } else { throw new Exception("Add group Error"); } } else { var newvalues = new List<string>() { Id }; Groups.Add(groupname, newvalues); } } public static void Remove(string groupname, string Id) { if (Groups.ContainsKey(groupname)) { if (Groups.TryGetValue(groupname, out var values)) { if (!values.Contains(Id)) return; values.Remove(Id); if (!(values.Count > 0)) Groups.Remove(groupname); } else { throw new Exception("Remove group Error"); } } } /// <summary> /// 连接断开时删除 /// </summary> /// <param name="Id"></param> public static void UnConnection(string Id) { Groups.Where(x=>x.Value.Contains(Id)).AsParallel().ForAll(x => x.Value.Remove(Id)); } } ``` tn2>在`ChatHub`中,添加可以调用组的方法 ```csharp public override Task OnDisconnectedAsync(Exception exception) { var id = Context.ConnectionId; UserIdsStore.Ids.Remove(id); _logger.LogInformation($"Client ConnectionId=> [[{id}]] Already Close Connection Server!"); // 删除相关组下的信息 GroupStore.UnConnection(Context.ConnectionId); return base.OnDisconnectedAsync(exception); } /// <summary> /// 添加组 /// </summary> /// <param name="groupName"></param> /// <returns></returns> public async Task AddToGroup(string groupName) { await Groups.AddToGroupAsync(Context.ConnectionId, groupName); // 按照组来发送消息 await Clients.Group(groupName).SendCustomUserMessage($"{Context.ConnectionId} has joined the group {groupName}."); GroupStore.Add(groupName, Context.ConnectionId); } /// <summary> /// 删除组 /// </summary> /// <param name="groupName"></param> /// <returns></returns> public async Task RemoveFromGroup(string groupName) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName); // 按照组来发送消息 await Clients.Group(groupName).SendCustomUserMessage($"{Context.ConnectionId} has left the group {groupName}."); GroupStore.Remove(groupName, Context.ConnectionId); } ``` tn2>在Vue客户端中,我们添加组和离开组的一些内容。 ```javascript <div> Group: <input type="text" v-model="group" > <button @click="onAddGroupButton" >加入组</button> <button @click="onRemoveGroupButton" >离开组</button> </div> ... onAddGroupButton() { var e = this signal .invoke('AddToGroup', e.group) .catch(function(err) {return console.error(err) }) }, onRemoveGroupButton() { var e = this signal .invoke('RemoveFromGroup', e.group) .catch(function(err) {return console.error(err) }) }, ``` ![](https://img.tnblog.net/arcimg/hb/e831be1ee8fe4b3381fa934546c6b333.png) ![](https://img.tnblog.net/arcimg/hb/a763ba25df12494585822664fada6351.png) tn2>断开第二个页面的链接(刷新一下),再次查看。 ![](https://img.tnblog.net/arcimg/hb/29eebebfd1044879ab58e8e47b836cb9.png) tn2>我们让bob用户离开aa组,再次查看。 ![](https://img.tnblog.net/arcimg/hb/08a3f5ed66264f9ba9ea321e41acefec.png) 使用实体发送消息 ------------ tn2>首先在后端定义我们的实体和服务器上的接口。 ```csharp public class TestModel { public string Message { get; set; } public string Email { get; set; } } ``` ```csharp /// <summary> /// 发送实体模型 ChatHub类中 /// </summary> /// <param name="data"></param> /// <returns></returns> public async Task SendTestModelMessage(TestModel data) { await Clients.All.SendTestModel(data); await Clients.Caller.SendAll(_common.SendCaller()); } ``` ```csharp public interface IChatClient { Task SendTestModel(TestModel model); } ``` tn2>更改客户端,在客户端中添加相关接口的发送与接收。 ```javascript <div> Message: <input type="text" v-model="message1" > Email: <input type="text" v-model="email" > <button @click="onModelClickButton" >发送实体</button> </div> ... message1: "", email: "", ... onModelClickButton() { var e = this signal .invoke('SendTestModelMessage',{ message: e.message1, email: e.email }) .catch(function(err) {return console.error(err) }) } ``` ![](https://img.tnblog.net/arcimg/hb/2820cb68c73c4e31bc46629a4b34f2cb.png) tn>最后建议在发送消息的时候使用:`ConfigureAwait`异步发送避免卡死现象。 tn>参考:https://zhuanlan.zhihu.com/p/424383788
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
👈{{preArticle.title}}
👉{{nextArticle.title}}
评价
{{titleitem}}
{{titleitem}}
{{item.content}}
{{titleitem}}
{{titleitem}}
{{item.content}}
尘叶心繁
这一世以无限游戏为使命!
博主信息
排名
6
文章
6
粉丝
16
评论
8
文章类别
.net后台框架
168篇
linux
17篇
linux中cve
1篇
windows中cve
0篇
资源分享
10篇
Win32
3篇
前端
28篇
传说中的c
4篇
Xamarin
9篇
docker
15篇
容器编排
101篇
grpc
4篇
Go
15篇
yaml模板
1篇
理论
2篇
更多
Sqlserver
4篇
云产品
39篇
git
3篇
Unity
1篇
考证
2篇
RabbitMq
23篇
Harbor
1篇
Ansible
8篇
Jenkins
17篇
Vue
1篇
Ids4
18篇
istio
1篇
架构
2篇
网络
7篇
windbg
4篇
AI
18篇
threejs
2篇
人物
1篇
嵌入式
2篇
python
13篇
HuggingFace
8篇
pytorch
9篇
opencv
6篇
Halcon
1篇
最新文章
最新评价
{{item.articleTitle}}
{{item.blogName}}
:
{{item.content}}
关于我们
ICP备案 :
渝ICP备18016597号-1
网站信息:
2018-2024
TNBLOG.NET
技术交流:
群号656732739
联系我们:
contact@tnblog.net
欢迎加群
欢迎加群交流技术