欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联

程序员文章站 2022-04-14 22:41:19
Signalr是以Group、Connect为核心来进行推送,比如,给某个组、某个连接来推送,但实际场景中,核心应该是某个组、某个人;然而一个人可以对应多个连接(浏览器多个tab页);本节就来介绍下自行管理人、组、连接这些关系 由于signalr连接的时候不那么方便附带header和cookie(因 ......

signalr是以group、connect为核心来进行推送,比如,给某个组、某个连接来推送,但实际场景中,核心应该是某个组、某个人;然而一个人可以对应多个连接(浏览器多个tab页);本节就来介绍下自行管理人、组、连接这些关系
由于signalr连接的时候不那么方便附带header和cookie(因为推送独立成一个子系统了),实际实现中采用以url query的形式附带上token,然后服务器端自定义解析token得到用户信息;

服务器端实现

  • configureservices中添加服务相关方法,代码如下,完整代码

    public void configureservices(iservicecollection services)
    {
        var appsection = configuration.getsection("app");
        services.configure<appsetting>(option => appsection.bind(option));
        var appsetting = appsection.get<appsetting>();
    
        services.addsingleton<signalrredishelper>();
    
        // services.addhostedservice<clearbackgroundservice>();
    
        services.addauthentication(options =>
        {
            options.defaultauthenticatescheme = jwtbearerdefaults.authenticationscheme;
            options.defaultchallengescheme = jwtbearerdefaults.authenticationscheme;
            options.defaultforbidscheme = jwtbearerdefaults.authenticationscheme;
        })
        .addjwtbearer(option =>
        {
            option.securitytokenvalidators.clear();
            option.securitytokenvalidators.add(new usertokenvalidation()); ;
    
            option.events = new jwtbearerevents()
            {
                onmessagereceived = context =>
                {
                    var userid = context.request.query["userid"].firstordefault();
                    if (!string.isnullorwhitespace(userid))
                    {
                        context.token = userid;
                    }
                    return task.completedtask;
                }
            };
        });
    
        services.addcors(options => options.addpolicy(corspolicy, builder =>
        {
            builder
                  .setisoriginallowedtoallowwildcardsubdomains()
                  .withorigins(appsetting.cors.split(","))
                  .allowanymethod()
                  .allowcredentials()
                  .allowanyheader()
                  .build();
        }));
    
        services.addcontrollers()
            .addnewtonsoftjson(options => options.serializersettings.contractresolver = new camelcasepropertynamescontractresolver())
            .configureapibehavioroptions(options =>
            {
                options.invalidmodelstateresponsefactory = context =>
                {
                    var result = new badrequestobjectresult(context.modelstate);
                    result.contenttypes.add(mediatypenames.application.json);
                    // result.contenttypes.add(mediatypenames.application.xml);
    
                    return result;
                };
            })
            .setcompatibilityversion(compatibilityversion.version_3_0);
    
        // 添加signalr
        services.addsignalr(config =>
        {
            if (_webenv.isdevelopment())
            {
                config.enabledetailederrors = true;
            }
        })
        // 支持messagepack
        .addmessagepackprotocol()
        // 使用redis做底板 支持横向扩展 scale-out
        .addstackexchangeredis(o =>
          {
              o.connectionfactory = async writer =>
              {
                  var config = new configurationoptions
                  {
                      abortonconnectfail = false,
                      // password = "changeme",
                      channelprefix = "__signalr_",
                  };
                  //config.endpoints.add(ipaddress.loopback, 0);
                  //config.setdefaultports();
                  config.defaultdatabase = appsetting.signalrrediscache.databaseid;
                  var connection = await connectionmultiplexer.connectasync(appsetting.signalrrediscache.connectionstring, writer);
                  connection.connectionfailed += (_, e) =>
                  {
                      console.writeline("connection to redis failed.");
                  };
    
                  if (connection.isconnected)
                  {
                      console.writeline("connected to redis.");
                  }
                  else
                  {
                      console.writeline("did not connect to redis");
                  }
    
                  return connection;
              };
          });
    }

    其中,signalrredishelper 为redis辅助方法,详情请参见
    usertokenvalidation 为自定义token解析方法,详情请参见,由于历史遗留问题,此处直接使用了userid,建议的做法是传递jwttoken,然后服务器端解析jwt token得到用户信息

hub中跟用户关联

在hub中通过context.user.identity.name可以获取到解析的值,通过这种关系来跟用户关联上,当然,也可以自定义修改使用其他信息,比如email或其他自定义的名称,具体请google

更多内容请通过快速导航查看下一篇

快速导航

标题 内容
索引 .net core 3.0 signalr - 实现一个业务推送系统
上一篇 .net core 3.0 signalr - 04 使用redis做底板来支持横向扩展
下一篇 .net core 3.0 signalr - 06 业务实现-业务分析
源码地址 源码
官方文档 官方文档

.net core 3.0 Signalr - 05 使用jwt将用户跟signalr关联