由于Azure ADB2C,Blazor服务器SignalR集线器在StartAsync上失败



我创建了一个Blazor服务器应用程序,试图开始学习Blazor和一些新技术。我遵循了微软的中心聊天教程。事情进展顺利。然后我添加了一些基本的cookie身份验证,事情仍然在不断发展。然后,我在Blazor Train上学习了Carl Franklin关于将应用程序连接到Azure AD B2C的教程。除了应用程序的聊天中心部分,它还能工作。该应用程序的所有其他部分都运行良好,并显示用户的信息。

我几乎可以肯定的是,"hubconnection"之所以失败,是因为它没有进行身份验证,因为它没有获得访问令牌。故障发生在await hubConnection.StartAsync();线上,错误为System.Text.Json.JsonReaderException: '<' is an invalid start of a value。我很确定HTML会返回403消息或类似的内容。

所以我想我有两个问题:

  1. 如何查看导致HubConnectionBuilder出错的value?即使我设置了断点,我也永远看不到导致它阻塞的值是什么。

  2. 如何将访问令牌传递给HubConnectionBuilder?

我发现了很多";"方式";做这件事要么已经过时,要么我无法工作:

使用已弃用的 AddAzureADB2CBearer

将参数传递到应用程序,我无法使用

适用于Azure AD,而非B2C

这就是使用Cookie auth:的原因

hubConnection = new HubConnectionBuilder()
.WithUrl(
NavigationManager.ToAbsoluteUri("/chathub"),
config => config.UseDefaultCredentials = true)
.Build();

现在,我似乎需要在这个关于Auth和SignalR但的Microsoft页面上传递一个访问令牌

hubConnection = new HubConnectionBuilder()
.WithUrl(
NavigationManager.ToAbsoluteUri("/chathub"), options =>
{
options.AccessTokenProvider = () => Task.FromResult(_myAccessToken);
})
.Build();

以下是我在Startup中所做的基于Carl Franklin YouTube视频的B2C工作

//****Azure B2C****//
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAdB2C"));

services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy
options.FallbackPolicy = options.DefaultPolicy;
});
services.AddRazorPages();
services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();

我也遇到了同样的问题,并设法使其正常工作。从组件连接时,我必须手动将身份验证cookie传递到集线器。

这是我的集线器类:

[Authorize]
public class NotificationsHub : Microsoft.AspNetCore.SignalR.Hub
{
public async override Task OnConnectedAsync() {
var user = Context.User;
var identifier = Context.UserIdentifier;
string name = Context.User.Claims.First(x => x.Type.Equals("name")).Value;
await base.OnConnectedAsync();
await Clients.Caller.SendAsync("Connected", 0);
}
}

然后我在Program.cs 中配置了它

app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapHub<NotificationsHub>("/notificationshub");
endpoints.MapFallbackToPage("/_Host");
});

我还将集线器配置为使用我的Microsoft cookie中的UserId:

services.AddSingleton<IUserIdProvider, SignalRUserIdProvider>();
public class SignalRUserIdProvider : IUserIdProvider
{
public virtual string GetUserId(HubConnectionContext connection) {
return connection.User?.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value!;
}
}

最后,我在连接到我的集线器时通过了cookie。示例组件:

@using Microsoft.AspNetCore.SignalR.Client
@using Microsoft.Extensions.Configuration
@implements IAsyncDisposable
@inject IHttpContextAccessor HttpContextAccessor;
@inject NavigationManager Navigate;
@code {
private HubConnection hubConnection;
protected override async Task OnInitializedAsync() {
hubConnection = new HubConnectionBuilder()
.WithUrl(Navigate.ToAbsoluteUri("/notificationshub"), options => {
if (HttpContextAccessor.HttpContext != null) {
foreach (var cookie in HttpContextAccessor.HttpContext.Request.Cookies) {
// IF THE DOMAIN PARAMETER IS WRONG YOU WILL RECEIVE THE JSON ERROR.
options.Cookies.Add(new Cookie(cookie.Key, cookie.Value, null, domain: "localhost"));
}
}
})
.WithAutomaticReconnect()
.Build();
hubConnection.On<int>("Connected", i => {
// Yay, it worked
StateHasChanged();
});
await hubConnection.StartAsync();
}
public async ValueTask DisposeAsync() {
if (hubConnection is not null) {
await hubConnection.DisposeAsync();
}
}
}

我已经很久没有遇到这个问题了,所以如果有什么不清楚的地方,请告诉我。

希望它能有所帮助!

最新更新