IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> wtm plus(.NET6)SignalR使用的身份验证和授权(cookie+jwt)的正确姿势 -> 正文阅读

[JavaScript知识库]wtm plus(.NET6)SignalR使用的身份验证和授权(cookie+jwt)的正确姿势

最近,需要开发即时通讯功能。于是,微软的实时通讯神器SignalR就是最好的选择。由于需要支持所有人发送、群聊和私聊。这样对于在hub的中获取用户身份就显得十分必要了。在wtm中我们采用itcode + ConnId的方式,缓存所有的连接,在私聊的时候用itcode找到对应的连接id就行了,这样可以有效的客户端防止刷新后,消息发送不正常的bug。具体的做法就不写了,其实用websocket也是这么干的。重点是如何在wtm的项目中,正确的通过cookie和jwt获取用户信息。

一、cookie方式

这个没啥好说的,正常的mvc项目中(wtm是layui)直接按照官方文档写js就行了,由于你自己继承的hub类,我这里是ChatHub: Hub,系统默认帮你注册过了。因此,咱们只需要通过在ChatHub构造函数中获取WTMContext就可以很舒服的拿到当前用户登录信息LoginUserInfo或者EFDataContext。具体还可以拿到什么,参照下图。详细看WTM官方的章节。

获取WTMContext写法就是,是不是简单粗暴。

public class ChatHub : Hub
    {


        private WTMContext _wTMContext { get; set; }
        public ChatHub(WTMContext wTMContext)
        {
            _wTMContext = wTMContext;
        }    
    }

使用的话,和控制器构造函数中获取的服务试用方法是一样的。

var itcode = _wTMContext.LoginUserInfo.ITCode;

二、JWT方式

?这个方法就是比较麻烦了,首先wtm plus默认注入的是AddWtmAuthentication,方法位于WalkingTec.Mvvm.Mvc命名空间下FrameworkServiceExtension静态类中。查看具体方法,对照微软的官网,我们发现,AddWtmAuthentication中只是缺少JwtBearerEvents关于SignalR的认证配置。也就是下面这一段。

 // Sending the access token in the query string is required due to
      // a limitation in Browser APIs. We restrict it to only calls to the
      // SignalR hub in this code.
      // See https://docs.microsoft.com/aspnet/core/signalr/security#access-token-logging
      // for more information about security considerations when using
      // the query string to transmit the access token.
      options.Events = new JwtBearerEvents
      {
          OnMessageReceived = context =>
          {
              var accessToken = context.Request.Query["access_token"];

              // If the request is for our hub...
              var path = context.HttpContext.Request.Path;
              if (!string.IsNullOrEmpty(accessToken) &&
                  (path.StartsWithSegments("/hubs/chat")))
              {
                  // Read the token out of the query string
                  context.Token = accessToken;
              }
              return Task.CompletedTask;
          }
      };

1、修改WtmAuthentication方法

我们新建一个MyFrameworkServiceExtension静态类,把创建AddMyWtmAuthentication静态方法,该方法先完全复制wtm的AddWtmAuthentication方法,然后把上面这点代码加进入。options.Authority = "Authority URL";这个得重点说下,官方文档上是有的,我把他注释了,这个坑货加上后强制要求https。

全部代码如下

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using System.Threading.Tasks;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Mvc.Auth;

namespace InnovationAlliance.Extension
{
    public static class MyFrameworkServiceExtension
    {
        public static IServiceCollection AddMyWtmAuthentication(this IServiceCollection services, IConfiguration config)
        {
            Configs configs = config.Get<Configs>();
            services.AddScoped<ITokenService, TokenService>();
            JwtOption jwtOptions = configs.JwtOptions;
            CookieOption cookieOptions = configs.CookieOptions;
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            services.AddAuthentication("Cookies").AddJwtBearer("Bearer", delegate (JwtBearerOptions options)
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role",
                    ValidateIssuer = true,
                    ValidIssuer = jwtOptions.Issuer,
                    ValidateAudience = true,
                    ValidAudience = jwtOptions.Audience,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey)),
                    ValidateLifetime = true
                };
                //options.Authority = "Authority URL";
                options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];

                        // If the request is for our hub...
                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) &&
                            (path.StartsWithSegments("/hubs/chat")))
                        {
                            // Read the token out of the query string
                            context.Token = accessToken;
                        }
                        return Task.CompletedTask;
                    }
                };


            }).AddCookie("Cookies", delegate (CookieAuthenticationOptions options)
            {
                options.Cookie.Name = CookieAuthenticationDefaults.CookiePrefix + "WTM.CookieWithJwtAuth";
                options.Cookie.HttpOnly = true;
                options.Cookie.SameSite = SameSiteMode.Strict;
                options.Cookie.Domain = (string.IsNullOrEmpty(cookieOptions.Domain) ? null : cookieOptions.Domain);
                options.ClaimsIssuer = cookieOptions.Issuer;
                options.SlidingExpiration = cookieOptions.SlidingExpiration;
                options.ExpireTimeSpan = TimeSpan.FromSeconds(cookieOptions.Expires);
                options.LoginPath = cookieOptions.LoginPath;
                options.LogoutPath = cookieOptions.LogoutPath;
                options.ReturnUrlParameter = cookieOptions.ReturnUrlParameter;
                options.AccessDeniedPath = cookieOptions.AccessDeniedPath;
            });
            return services;
        }

    }
}

2、给ChatHub打上wtm的身份认证特性标签

    [AuthorizeJwtWithCookie]
    public class ChatHub : Hub
    {
        private WTMContext _wTMContext { get; set; }
        public ChatHub(WTMContext wTMContext)
        {
            _wTMContext = wTMContext;
        }    
    }

3、js客户端上accessTokenFactory方法传递access_token,access_token就是那种没有Bearer的那种。一下是一段uniapp使用jwt的代码。

let token = uni.getStorageSync('token');
			 this.connection = new HubConnectionBuilder()
				.withUrl("http://localhost:48936/chathub", {
					accessTokenFactory: () => {
					    return token.replace ('Bearer ',"");
					}
				})
				.configureLogging(LogLevel.Trace)
				.build();


			this.start();
			this.connection.on("FriendsOnline", function(message) {
				console.log("收到的消息" + message);
			});

			this.connection.onclose(function() { //去掉斜杠
				console.log("websocket连接断开");
				//重试
				this.start();
			});

4、在?Startup中,用自己写的AddMyWtmAuthentication,替换原来的AddWtmAuthentication

services.AddMyWtmAuthentication(ConfigRoot);

经过一天的踩坑调试终于成功了。

用wtmplus,对于新手来说是个很好的过度时期,在线可视化制作项目。同时,还能得到微软MVP刘亮的一对一指导,可以在一个相对舒服的环境里完成项目。

有兴趣的可以去wtmplus官网,体验一下.NET在线开发。
传送门http://wtmplus.walkingtec.cn/index.html#/
?

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:31:32  更:2022-05-09 12:34:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:40:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码