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 業務實現-業務分析 |
| 源碼地址 | 源碼 |
| 官方文檔 | 官方文檔 |

