簡體   English   中英

Blazor WebAssembly SignalR 身份驗證

[英]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();

但沒有喜悅。

我遇到了同樣的問題。

我的解決方案是雙面的:我必須在前端和后端修復一些東西。

Blazor

在您的連接構建器中,您應該添加 AccessTokenProvider:

string accessToken = "eyYourToken";
connection = new HubConnectionBuilder()
    .WithUrl("https://localhost:5001/hub/chat", options =>
    {
        options.AccessTokenProvider = () => Task.FromResult(token.Value);
    })
    .Build();

options.AccessTokenProviderFunc<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),我必須添加以下內容:

Blazor WASM 客戶端

建立連接時(在我的例子中:在某些服務代理類的構造函數中),使用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();
}

ASP.NET核心服務器

將以下內容添加到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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM