Gabriel Weidmann
Gabriel Weidmann

Reputation: 887

How can I use windows NTLM auth for blazor webassembly SignalR

In one of my current projects we decided to give blazor webassembly a try, as blazor serverside works great, but of course got some latency when interacting with the web controls due to all of the logical calculations happening serverside.

One of the largest problems is that we are using our internal windows auth for all of the companies apps in the intranet. It's just stated that it should work, but the official documentations example didn't work in our experiments. The project throws an PlatformNotSupportedException due to the UseDefaultCredentials = true is not supported on browsers.

How can I subscribe to a signalR hub on my server from a webassembly client using blazor and windows NTLM auth?

Upvotes: 2

Views: 68

Answers (1)

Gabriel Weidmann
Gabriel Weidmann

Reputation: 887

We already solved the problem of calling the api with windows auth. So I tried to use the same mechanism for setting up the signalR connection, and voilà: It worked :-)

Here is the relevant excerpt from the test projects clientside code:

Program.cs

var builder = WebAssemblyHostBuilder.CreateDefault(args);

...

builder.Services.AddTransient<WindowsAuthenticationDelegatingHandler>();

// Use windows auth for api calls
builder.Services.AddHttpClient<IApiClient, ApiClient>()
       .AddHttpMessageHandler<WindowsAuthenticationDelegatingHandler>();

// Use windows auth for signalR
builder.Services.AddSingleton<SignalRReciever>();

...

WindowsAuthenticationDelegatingHandler.cs

using Microsoft.AspNetCore.Components.WebAssembly.Http;

public class WindowsAuthenticationDelegatingHandler : DelegatingHandler
{
    protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // This is required to include the windows authentication token in the request.
        request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
        return base.Send(request, cancellationToken);
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // This is required to include the windows authentication token in the request.
        request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
        return base.SendAsync(request, cancellationToken);
    }
}

SignalRReciever.cs

using Microsoft.AspNetCore.SignalR.Client;
...

public class SignalRReciever
{
    private readonly HubConnection _hubConnection;

    public SignalRReciever(WindowsAuthenticationDelegatingHandler windowsAuthHandler, ILogger<SignalRReciever> logger)
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl("http://someapi.de/itemhub", options =>
            {
                // Wrap handler with windows auth
                options.HttpMessageHandlerFactory = innerHandler =>
                {
                    windowsAuthHandler.InnerHandler = innerHandler;
                    return windowsAuthHandler;
                };
            })
            .Build();

        _hubConnection.On<string, object>("ItemChanged", (user, message) =>
        {
            logger.LogInformation("Recieved ItemChanged message from user {User}: {Message}",
                user, message);
        });

        logger.LogInformation("Start listening to SignalR");

        _ = _hubConnection.StartAsync().ContinueWith(t =>
        {
            logger.LogInformation("Connection resulted in: {Status}\n{Exception}",
                t.Status, t.Exception);
        });
    }
}

Upvotes: 2

Related Questions