0

When using SignalR core locally I am able to access my identity claims principle via the Hub using HubCallerContext, e.g:

string userIdentifier = Context.UserIdentifier 

I achieve this by passing the .AspNetCore.Identity.Application cookie to the HubConnectionBuilder:

 hubConnection = new HubConnectionBuilder()
    .WithUrl(Navigation.ToAbsoluteUri("/chathub"), options =>
     {
          options.Cookies = GetAuthCookieContainer();
     })
    .Build();
    await hubConnection.StartAsync();

    private CookieContainer GetAuthCookieContainer()
    {
        string cookieName = ".AspNetCore.Identity.Application";
        string domainName = new Uri(Navigation.BaseUri).Host;
        CookieContainer cookieContainer = new CookieContainer();
        if (HttpContext.HttpContext != null)
        {
            var token = HttpContext.HttpContext.Request.Cookies[cookieName];
            if (token != null)
            {
                cookieContainer.Add(new Cookie(cookieName, token) { Domain = domainName });
            }
        }
        return cookieContainer;
    } 

This stops working once I add Azure SignalR service to Program.cs:

builder.Services.AddSignalR().AddAzureSignalR();

This is because I cannot pass the identity cookie to HubConnectionBuilder as HttpContext is always null once Azure SignalR is added to DI. Apart from this SignalR Azure works as expected.

Does anyone have a solution to how I can pass AspNetCore.Identity.Application cookie to HubConnectionBuilder() when using Azure SignalR or is there a better approach to this problem?

jbob77435
  • 147
  • 1
  • 10
  • 1
    [Does the answer useful to you ?](https://stackoverflow.com/a/75172631/7687666) – Jason Pan Aug 30 '23 at 07:06
  • 1
    Thanks. This look promising if httpcontext can be used in _Host.cshtml before blazor creates its circuit. I'll give it a try and report back. – jbob77435 Aug 30 '23 at 09:04
  • 1
    If it works for you, please allow me summarize it as answer, thanks – Jason Pan Aug 30 '23 at 09:21
  • It worked, I wrote my solution below using a slightly different approach I found on YouTube, but please feel free to add a summary answer and I'll mark it as the excepted solution as the approach is essentially the same. – jbob77435 Aug 31 '23 at 10:14
  • Hi jbob77435, I have summarize the issue and give the way of setting as CascadingValue to achieve that. Thanks for your effort. – Jason Pan Aug 31 '23 at 11:47

2 Answers2

1

Problem

HttpContext is null once Azure SignalR service is added to DI.

Solution

  1. Create a scoped service to store properties from HttpContext and add to program.cs:
builder.Services.AddScoped<IdentityInformation>();
  1. Within _Host.cstml create an object (InitialApplicationState) to store your desired parameters from HttpContext and then pass this object to your App component as a parameter:
var state = new InitialApplicationState();
state.IsAuthenticated = HttpContext.User.Identity.IsAuthenticated;
...
<component type="typeof(App)" param-InitialState="state" render-mode="ServerPrerendered" /> 
  1. Within App.razor add a parameter property to store the arguments sent from _Host.cshtml and then assign them to your injected service:
    @inject IdentityInformation identityInformation

    [Parameter]
    public InitialApplicationState InitialState { get; set; }

     protected override void OnInitialized()
     {
        identityInformation.IsAuthenticated = InitialState.IsAuthenticated;
     }

  1. You can now inject the 'IdentityInformation' service and safely access your stored HttpContext properties from anywhere within your Blazor app.

Many thanks to the codewrinkles YouTube channel for the solution: https://www.youtube.com/watch?v=Eh4xPgP5PsM

jbob77435
  • 147
  • 1
  • 10
1

The major problem is that in Blazor Server we can't access the HttpContext directly, as it is not guaranteed that IHttpContextAccessor will have an instance of the context and it is also not guaranteed that if it has an instance.

We should grab the values from HttpContext object in _Host.cshtml file, create a new object and store the values, then pass this object to the App component as a parameter.

Then we can set them as a CascadingValue or create a scoped service to store properties from HttpContext and add to program.cs.

jbob77435's answer is using DI to access the stored HttpContext properties from anywhere within the Blazor app.

We also could use

[CascadingParameter(Name = "Cookies")] public Dictionary<string, string> Cookies { get; set; }

to implement it.

Hope this official blog will useful to you.

Solution: Custom SignalR Endpoints (Hubs) in a Blazor Server Application using Azure B2C When Deployed to Azure

Jason Pan
  • 15,263
  • 1
  • 14
  • 29