Аутентификация Blazor WebAssembly SignalR - PullRequest
1 голос
/ 29 мая 2020

Мне бы хотелось увидеть пример того, как добавить аутентификацию к подключению концентратора SignalR с использованием разновидности WebAssembly Blazor. Моя версия do tnet - 3.1.300.

Я могу выполнить следующие действия, чтобы получить открытое неаутентифицированное соединение SignalR: https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr-blazor-webassembly?view=aspnetcore-3.1&tabs=visual-studio

Все руководства Я считаю, что они старше или относятся к типу, размещенному на сервере, и не использую встроенный шаблон.

Я добавил аутентификацию в остальную часть серверной части, используя соответствующий шаблон и эти инструкции , включая базу данных: https://docs.microsoft.com/en-us/aspnet/core/security/blazor/?view=aspnetcore-3.1

Но каждый раз, когда я добавляю [Authenticate] в чат, я получаю сообщение об ошибке. Есть ли способ, расширяя первое руководство, чтобы мы могли аутентифицировать созданный там концентратор? Было бы здорово подключиться к встроенной системе ASP. NET, но я могу просто передать токен в качестве дополнительного параметра и сделать это сам, если это лучше всего. В этом случае мне нужно было бы узнать, как получить токен из Blazor WebAssembly, а затем найти его где-нибудь на сервере. Это кажется неправильным, но это в основном удовлетворило бы мои потребности в качестве альтернативы. представляет.

Обновление: Следуя подсказкам в этом выпуске новостей https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-2-release-now-available/, теперь я могу получить токен изнутри страницы бритвы и вставить его в заголовок. Думаю, это хорошо ?? Но тогда как мне получить его и использовать на сервере?

Вот фрагмент кода бритвы:

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();

Но без радости.

Ответы [ 2 ]

0 голосов
/ 28 июля 2020

Это работает с собственным сервером идентификации WebAssembly с атрибутом [Authorize] на хабе.

Что важно, так это настройка концентратора для доступа к токену. Затем концентратор может использовать любой протокол, который ему нужен для отправки токена на сервер при запуске.

 hubConnection = new HubConnectionBuilder()
            .WithUrl(NavigationManager.ToAbsoluteUri("/chathub"), options =>
            {
                options.AccessTokenProvider = async () =>
                {
                    var accessTokenResult = await AccessTokenProvider.RequestAccessToken();
                    accessTokenResult.TryGetToken(out var accessToken);
                    return accessToken.Value;
                };
            })
            .Build();

Полная страница, которую я адаптировал из руководств 3.1 SignalR.

@using Microsoft.AspNetCore.SignalR.Client
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Microsoft.AspNetCore.Authorization

@page "/chat"
@attribute [Authorize]
@implements IDisposable

<div class="form-group">
    <label>
        User:
        <input @bind="userInput" />
    </label>
</div>
<div class="form-group">
    <label>
        Message:
        <input @bind="messageInput" size="50" />
    </label>
</div>
<button @onclick="Send" disabled="@(!IsConnected)">Send</button>

<hr>

<ul id="messagesList">
    @foreach (var message in messages)
    {
        <li>@message</li>
    }
</ul>

@code {
    private HubConnection hubConnection;
    private List<string> messages = new List<string>();
    private string userInput;
    private string messageInput;

    [Inject]
    public NavigationManager NavigationManager { get; set; }

    [Inject]
    public IAccessTokenProvider AccessTokenProvider { get; set; }

    protected override async Task OnInitializedAsync()
    {

        hubConnection = new HubConnectionBuilder()
            .WithUrl(NavigationManager.ToAbsoluteUri("/chathub"), options =>
            {
                options.AccessTokenProvider = async () =>
                {
                    var accessTokenResult = await AccessTokenProvider.RequestAccessToken();
                    accessTokenResult.TryGetToken(out var accessToken);
                    return accessToken.Value;
                };
            })
            .Build();

        hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
        {
            var encodedMsg = $"{user}: {message}";
            messages.Add(encodedMsg);
            StateHasChanged();
        });

        await hubConnection.StartAsync();
    }

    Task Send() =>
        hubConnection.SendAsync("SendMessage", userInput, messageInput);

    public bool IsConnected =>
        hubConnection.State == HubConnectionState.Connected;

    public void Dispose()
    {
        _ = hubConnection.DisposeAsync();
    }
}
0 голосов
/ 23 июля 2020

Это мое решение и работает

[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;
        });
    }
}
...