Properly Authorizing/Protecting Signalr Core Hub

124 Views Asked by At

I am trying to setup Blazor Server with a Signal R Core hub using Azure SignalR Services.

In general the Blazor app is working fine and is using Azure SignalR Services.

The Signal R Core Hub will work if I decorate it using [AllowAnonymous]. If I remove the [AllowAnonymous] the Signalr R Core client's HubConnection StartAsync gives a variety of errors depending on what I adjust in startup.cs. Using Fiddler I can tell the StartAsync attempts to retrieve a token from login.microsoftonline.com.

I don't understand why the currently logged in and authorized isn't being used.

Even when I use [AllowAnonymous] the Signalr R Hub will pickup the the username.

Here is the code for the Hub:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Authorization;

namespace ServerApp.Services.NotificationHub
{
    [AllowAnonymous]
    public class BlazorChatHub : Hub
    {
        public const string HubUrl = "/coaching";

        private ILogger<BlazorChatHub> _logger;

        public BlazorChatHub(ILogger<BlazorChatHub> logger)
        {
            _logger = logger;
        }
        
        public async Task Broadcast(string username, string message)
        {
            _logger.LogInformation($"Broadcast: {username} : {message}");
            await Clients.All.SendAsync("Broadcast", username, message);
        }

        
        public async Task Send(string message)
        {
            await Clients.All.SendAsync("Send", message);
        }

        
        public async Task SendMessage(string user, string message)
        {
            _logger.LogInformation($"SendMessage: {user} : {message}");
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }

        
        public override Task OnConnectedAsync()
        {
            _logger.LogInformation($"{Context.ConnectionId} connected");

            return base.OnConnectedAsync();
        }
        
        public override async Task OnDisconnectedAsync(Exception e)
        {
            _logger.LogInformation($"Disconnected {e?.Message} {Context.ConnectionId}");                
            await base.OnDisconnectedAsync(e);
        }
    }
}

Here is the code for the Blazor page where the Hub is opened. _hubConnection.StartAsync() fails if I remove the [AllowAnonymous] from the Hub shown above.

// Create the chat client
string baseUrl = navigationManager.BaseUri;

_hubUrl = baseUrl.TrimEnd('/') + BlazorChatHub.HubUrl;
    
_hubConnection = new HubConnectionBuilder()
    .WithUrl(_hubUrl)
    .Build();

_hubConnection.On<string, string>("Broadcast", BroadcastMessage);

await _hubConnection.StartAsync();

From Startup.cs, I believe this is where the problem may originate:

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
        {
            Configuration.Bind("AzureAd", options);                
        })
    .EnableTokenAcquisitionToCallDownstreamApi() //initialScopes
        .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
    .AddInMemoryTokenCaches();

Almost as if the Hub is considered a downstreamapi, when it is actually on the same Blazor Server app. Why is Blazor Server trying to go to login.microsoftonline.com to re-authenticate for "localhost/coaching/negotiate"?

0

There are 0 best solutions below