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 业务实现 - 业务分析 |
源码地址 | 源码 |
官方文档 | 官方文档 |