为啥我无法通过 Web 套接字连接获得 HubCallerContext 用户?

Posted

技术标签:

【中文标题】为啥我无法通过 Web 套接字连接获得 HubCallerContext 用户?【英文标题】:Why I can't get the HubCallerContext user with web sockets connections?为什么我无法通过 Web 套接字连接获得 HubCallerContext 用户? 【发布时间】:2022-01-12 05:58:36 【问题描述】:

当我使用 WebSockets 时,我无法在服务器上获取 userId

客户端代码:

    HubConnection = new HubConnectionBuilder().WithUrl(Config.BaseUrl + ApplicationConstants.SignalR.HubUrl, options =>
    
        options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
        options.Headers.Add("Authorization", $"Bearer NPCompletApp.Token");
        options.AccessTokenProvider = async () => await Task.FromResult(NPCompletApp.Token);
    ).WithAutomaticReconnect().Build();

服务器代码:

public override async Task<Task> OnConnectedAsync()
        

            ConnectedUserModel connectedUserModel = new ConnectedUserModel() 
             
                ConnectionId = Context.ConnectionId, UserId = _userManager.GetUserId(Context.User)
            ;

            UserHandler.connectedUsers.Add(connectedUserModel);

            var temp = new List<string>();

            foreach(ConnectedUserModel connectedUser in UserHandler.connectedUsers)
            
                if (!String.IsNullOrEmpty(connectedUserModel.UserId) && temp.Find(x=> x == connectedUserModel.UserId) == null)
                
                    temp.Add(connectedUserModel.UserId);
                    await OnConnectAsync(connectedUserModel.UserId);

                
            

            
            

            return base.OnConnectedAsync();
        

好在如果用户断开连接我可以捕捉到,但仍然不知道用户是谁。

服务器代码(断开连接时):

 public override async Task<Task> OnDisconnectedAsync(Exception? exception)
        

            var connection =  UserHandler.connectedUsers.Find(x => x.ConnectionId == Context.ConnectionId);

            await OnDisconnectAsync(connection.UserId);

            UserHandler.connectedUsers.Remove(connection);

            return base.OnDisconnectedAsync(exception);
        

另一方面,当我使用 LongPolling 时,我可以获得 userId,但在断开连接时我无法捕捉到他

客户端代码:

    HubConnection = new HubConnectionBuilder().WithUrl(Config.BaseUrl + ApplicationConstants.SignalR.HubUrl, options =>
    

        options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.LongPolling;
        options.Headers.Add("Authorization", $"Bearer NPCompletApp.Token");
        options.AccessTokenProvider = async () => await Task.FromResult(NPCompletApp.Token);
    ).WithAutomaticReconnect().Build();

我该怎么办?我想知道我的上下文中的用户是谁,并在他断开连接时抓住他。

【问题讨论】:

【参考方案1】:

您必须在您的服务器上配置中间件。

这是取自一个工作项目...

服务器:

services.TryAddEnumerable(
    ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>,
    ConfigureJwtBearerOptions>());

ConfigureJwtBearerOptions.cs

    public class ConfigureJwtBearerOptions : IPostConfigureOptions<JwtBearerOptions>
    
        private readonly ChatConfigurations config;

        public ConfigureJwtBearerOptions(ChatConfigurations config)
        
            this.config = config;
        

        public void PostConfigure(string name, JwtBearerOptions options)
        
            var originalOnMessageReceived = options.Events.OnMessageReceived;
            options.Events.OnMessageReceived = async context =>
            
                await originalOnMessageReceived(context);

                if (string.IsNullOrEmpty(context.Token)) 

                    var accessToken = context.Request.Query["access_token"];
                    var requestPath = context.HttpContext.Request.Path;
                    var endPoint = $"/config.EndPoint";

                    if (!string.IsNullOrEmpty(accessToken) &&
                        requestPath.StartsWithSegments(endPoint)) 
                        context.Token = accessToken;
                    
                
            ;
        
    

在您的客户端中,您还必须配置令牌。

public async ValueTask InitialiseAsync()

    IsInitialised = false;
    hubConnection = CreateHubConnection();

    hubConnection.On<string, string>("ReceiveMessage", ReceiveMessageAsync);

    ....

    await hubConnection.StartAsync();
    await hubConnection.SendAsync("JoinGroup", roomName);

    IsInitialised = true;



private HubConnection CreateHubConnection()

    var endPoint = $"/config.EndPoint";
    var hubConnection = new HubConnectionBuilder()
         .WithUrl(navigationManager.ToAbsoluteUri(endPoint), options =>
         
             options.AccessTokenProvider = async () =>
             
                 var accessTokenResult = await accessTokenProvider.RequestAccessToken();
                 accessTokenResult.TryGetToken(out var accessToken);
                 var token = accessToken.Value;
                 return token;
             ;
         )
         .WithAutomaticReconnect()
         .Build();

    return hubConnection;

我的集线器OnConnectedAsync

public async override Task OnConnectedAsync()

    logger.LogDebug("Hub Connection");
    await chatService.RegisterConnectionAsync(Context.ConnectionId, Context.UserIdentifier);
    await base.OnConnectedAsync();


注意:我正在保持与数据库的连接。

我的集线器OnDisconnectedAsync

public async override Task OnDisconnectedAsync(Exception exception)

    logger.LogDebug("Hub Disconnect");
    await chatService.RegisterDisconnectAsync(Context.ConnectionId);
    await base.OnDisconnectedAsync(exception);

一些调试日志:

dbug: OrakTech.ChatServer.Brokers.Loggings.LoggingBroker[0]
      Hub Connection
dbug: OrakTech.ChatServer.Brokers.Loggings.LoggingBroker[0]
      Hub Connected (r7SJaAMEGs7eovH810H5Xg, c8f81673-d8b3-4e46-80f6-a83b671e6ff1)
dbug: OrakTech.ChatServer.Brokers.Loggings.LoggingBroker[0]
      Join Group (TestRoom : r7SJaAMEGs7eovH810H5Xg)
dbug: OrakTech.ChatServer.Brokers.Loggings.LoggingBroker[0]
      Hub Disconnect
dbug: OrakTech.ChatServer.Brokers.Loggings.LoggingBroker[0]
      Hub Disconnect (r7SJaAMEGs7eovH810H5Xg)

【讨论】:

非常感谢❤️

以上是关于为啥我无法通过 Web 套接字连接获得 HubCallerContext 用户?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当它是静态连接时,Web 套接字的延迟会有所不同?

Web服务器可以处理多少个套接字连接?

使用 AJAX 无法获得的 HTML5 Web 套接字有啥好处?

在Python中,当在localhost上接受TCP套接字连接时,无法获得正确的对等体IP地址。

驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接 异常解决方法

为啥我无法通过 Prolog 获得 Ship Puzzle 的答案?