[英]Blazor WebAssembly SignalR Authentication
我希望看到一個示例,說明如何使用 Blazor 的 WebAssembly 風格向 SignalR 集線器連接添加身份驗證。 我的 dotnet 版本是 3.1.300。
我可以按照這些步驟來獲得一個開放的、未經身份驗證的 SignalR 連接工作: https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr-blazor-webassembly?view=aspnetcore-3.1&tabs=visual工作室
我發現的所有教程似乎都較舊或用於服務器托管類型,並且不使用內置模板。
我已使用適當的模板和這些說明(包括數據庫)向后端的 rest 添加了身份驗證: https://docs.microsoft.com/en-us/aspnet/core/security/blazor/?view= aspnetcore-3.1
但是每次我將 [Authenticate] 添加到聊天中心時,都會返回一個錯誤。 有什么方法可以擴展第一個教程,我們可以驗證那里創建的集線器? 搭上內置的 ASP.NET 系統會很棒,但是如果最好的話,我可以將令牌作為附加參數傳入並自己做。 在這種情況下,我需要學習如何從 Blazor WebAssembly 中獲取令牌,然后在服務器上的某個位置查找它。 這似乎是錯誤的,但作為替代方案,它基本上可以滿足我的需求。
那里有各種各樣的半解決方案,或者是為舊版本設計的,但沒有任何東西可以建立在 MS 提供的庫存教程之上。
更新:按照本新聞稿https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-2-release-now-available/中的提示,我現在可以從內部獲取令牌razor 頁面,並將其注入 header。 我想這很好?? 但是,我如何獲取它並在服務器上使用它呢?
這是 razor 代碼的片段:
protected override async Task OnInitializedAsync()
{
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(UriHelper.BaseUri);
var tokenResult = await AuthenticationService.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}");
hubConnection = new HubConnectionBuilder()
.WithUrl(UriHelper.ToAbsoluteUri("/chatHub"), options =>
{
options.AccessTokenProvider = () => Task.FromResult(token.Value);
})
.Build();
}
}
更新 2:我在這里嘗試了提示: https://github.com/dotnet/aspnetcore/issues/18697
並將我的代碼更改為:
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/chatHub?access_token=" + token.Value))
.Build();
但沒有喜悅。
我遇到了同樣的問題。
我的解決方案是雙面的:我必須在前端和后端修復一些東西。
在您的連接構建器中,您應該添加 AccessTokenProvider:
string accessToken = "eyYourToken";
connection = new HubConnectionBuilder()
.WithUrl("https://localhost:5001/hub/chat", options =>
{
options.AccessTokenProvider = () => Task.FromResult(token.Value);
})
.Build();
options.AccessTokenProvider
是Func<Task<string>>
類型,因此您也可以在此處執行異步操作。 如果需要的話。
僅這樣做,應該允許 SignalR 工作。
然而! 當 SignalR 嘗試創建 WebSocket 連接時,您可能仍會看到錯誤。 這是因為您可能在后端使用 IdentityServer,而這不支持來自查詢字符串的 Jwt 令牌。 不幸的是 SignalR 試圖通過名為access_token
的查詢字符串參數授權 websocket 請求。
將此代碼添加到您的啟動中:
.AddJwtBearer("Bearer", options =>
{
// other configurations omitted for brevity
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"))) // Ensure that this path is the same as yours!
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
編輯 1 :闡明 Blazor SignalR 代碼的用法
這是我的解決方案並且有效
[Inject] HttpClient httpClient { get; set; }
[Inject] IAccessTokenProvider tokenProvider { get; set; }
HubConnection hubConnection { get; set; }
(...)
private async Task ConnectToNotificationHub()
{
string url = httpClient.BaseAddress.ToString() + "notificationhub";
var tokenResult = await tokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
hubConnection = new HubConnectionBuilder().WithUrl(url, options =>
{
options.Headers.Add("Authorization", $"Bearer {token.Value}");
}).Build();
await hubConnection.StartAsync();
hubConnection.Closed += async (s) =>
{
await hubConnection.StartAsync();
};
hubConnection.On<string>("notification", m =>
{
string msg = m;
});
}
}
就我而言(Blazor WebAssembly,托管在 ASP.NET Core 5.0 上,使用 JWT Bearer Token Auth),我必須添加以下內容:
建立連接時(在我的例子中:在某些服務代理類的構造函數中),使用IAccessTokenProvider
並配置AccessTokenProvider
選項,如下所示:
public ServiceProxy(HttpClient httpClient, IAccessTokenProvider tokenProvider) {
HubConnection = new HubConnectionBuilder()
.WithUrl(
new Uri(httpClient.BaseAddress, "/hubs/service"),
options => {
options.AccessTokenProvider = async () => {
var result = await tokenProvider.RequestAccessToken();
if (result.TryGetToken(out var token)) {
return token.Value;
}
else {
return string.Empty;
}
};
})
.WithAutomaticReconnect() // optional
.Build();
}
將以下內容添加到Startup.ConfigureServices
:
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options => {
// store user's "name" claim in User.Identity.Name
options.TokenValidationParameters.NameClaimType = "name";
// pass JWT bearer token to SignalR connection context
// (from https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-5.0)
options.Events = new JwtBearerEvents {
OnMessageReceived = context => {
var accessToken = context.Request.Query["access_token"];
// If the request is for on of our SignalR hubs ...
if (!string.IsNullOrEmpty(accessToken) &&
(context.HttpContext.Request.Path.StartsWithSegments("/hubs/service"))) {
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.