【问题标题】:SignalR UserIdentifier is null in OnConnected method在 OnConnected 方法中 SignalR UserIdentifier 为空
【发布时间】:2022-01-26 00:18:18
【问题描述】:

我正在开发一个 blazor Web 程序集应用程序,我想使用 SignalR 发送推送通知。我可以建立连接并向所有用户发送通知,但我遇到了问题。我想在用户连接到应用程序时存储用户信息。在 OnConnected 方法中,我可以访问 ConnectionId 但 UserIdentifier 为空。我关注这个link。但什么也没发生,它仍然为空。

此代码在客户端建立连接:

    public async Task<bool> ConnectToNotificationHub()
    {
        bool isConnected = false;
        string url = $"{_configuration["APIBaseURL"]}/hubs/notificationhub";
        string token = await _localStorageService.GetItemAsStringAsync("user_account");

        if (!string.IsNullOrEmpty(token))
        {
            HubConnection hubConnection = new HubConnectionBuilder()
                .WithUrl(url, options =>
                {
                    options.AccessTokenProvider=() => Task.FromResult(token);
                })
                .Build();

            await hubConnection.StartAsync();
            isConnected=true;

            hubConnection.Closed+=async (s) =>
            {
                isConnected=false;
                await hubConnection.StartAsync();
                isConnected=true;
            };

            hubConnection.On<string>("notification", m =>
            {
                _notifications.Add(m);
                OnNotificationRecieved(null, null);
            });
        }

        return isConnected;
    }

这是 api 项目中的 Configure 方法:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseCors("PMS_API");

        app.UseMiddleware<CustomExceptionHandlerMiddleware>();

        if (env.IsDevelopment())
        {
            //app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "PMS.WebAPI v1"));
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<NotificationHub>("/hubs/notificationhub");
            endpoints.MapControllers();
        });
    }

这是我的中心:

    public class NotificationHub : Hub
{
    [Authorize]
    public override Task OnConnectedAsync()
    {
        Debug.WriteLine($"ConnectionId: {Context.ConnectionId} - UserIdentifier: {Context.UserIdentifier}"); // TODO: UserIdentifier is empty
        return base.OnConnectedAsync();
    }
}

这是身份事件:

                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")))
                        {
                            // Read the token out of the query string
                            context.Token = accessToken;
                        }
                        return Task.CompletedTask;
                    },
                    OnAuthenticationFailed = context =>
                    {
                        if (context.Exception != null)
                        {
                            throw new AppException(HttpStatusCode.Unauthorized, "Autentication failed.", context.Exception);
                        }

                        return Task.CompletedTask;
                    },
                    OnChallenge = context =>
                    {
                        if (context.AuthenticateFailure != null)
                        {
                            throw new AppException(HttpStatusCode.Unauthorized, "Autentication failed.", context.AuthenticateFailure);
                        }

                        throw new AppException(HttpStatusCode.Unauthorized, "You are unauthorized to access this resource.", null);
                    },
                    OnTokenValidated = async context =>
                    {
                        var claimsIdentity = context.Principal.Identity as ClaimsIdentity;
                        var signInManager = context.HttpContext.RequestServices.GetRequiredService<SignInManager<User>>();
                        var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<User>>();

                        if (!claimsIdentity.Claims.Any())
                        {
                            context.Fail("No claims were found.");
                        }

                        var securityStampClaim = claimsIdentity.FindFirst(new ClaimsIdentityOptions().SecurityStampClaimType);

                        if (securityStampClaim is null)
                        {
                            context.Fail("No security stamp was found.");
                        }

                        var validatedSecurityStamp = await signInManager.ValidateSecurityStampAsync(context.Principal);

                        if (validatedSecurityStamp is null)
                        {
                            context.Fail("Security stamp is not valid.");
                        }

                        var userIdClaim = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier);

                        if (userIdClaim is null)
                        {
                            context.Fail("User id claim was not found.");
                        }

                        var userId = userIdClaim.Value;
                        var user = await userManager.FindByIdAsync(userId);

                        if (user.LastCreatedToken is null)
                        {
                            context.Fail("User not logged in.");
                        }

                        if (user.LastTokenExpireDate is not null && user.LastTokenExpireDate < DateTime.Now)
                        {
                            context.Fail("User last token has expired.");
                        }

                        if (!user.IsActive)
                        {
                            context.Fail("User is not active.");
                        }

                        user.LastLoginDate = DateTime.Now;
                        await userManager.UpdateAsync(user);
                    }
                };

你能帮帮我吗?

谢谢

【问题讨论】:

  • [Authorize] 放在集线器类而不是 OnConnectedAsync 方法上
  • @Brennan 我更改了 [Authorize] 属性的位置,但是现在当我尝试建立连接时,api 应用程序停止并在 OnChallenge 事件中引发异常。我在问题中添加了身份事件。
  • 谢谢@Brennan,我找到了问题。

标签: c# asp.net-core signalr asp.net-core-webapi blazor-webassembly


【解决方案1】:

我终于找到了问题所在。感谢@Brenen 的评论,我应该将 [Authorize] 属性放在集线器类上。之后我意识到我向服务器发送了错误的令牌。我的 user_account 本地存储有其他数据,我将其作为令牌发送。我应该发送令牌部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多