HttpContextAccessor not found in Blazor Wasm app with authentication

wavemaster 311 Reputation points
2021-06-02T21:26:01.107+00:00

This is a Blazor Wasm app from a VS2019 template with Authentication/Authorization.

I need to know who the user is that is logged in.

User = HttpContextAccessor.HttpContext.User.Identity.Name;

HttpContextAccessor has a squiggle with cannot be found complaint.

My page has:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using System.Security.Claims
@attribute [Authorize]

@inject HttpClient http
@inject NavigationManager navManager
@inject ISnackbar Snackbar
@inject IDialogService DialogService
@inject IHttpContextAccessor HttpContextAccessor

Program.Main in the Client project has:
builder.Services.AddHttpContextAccessor();

What am I doing wrong here?

Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,577 questions
0 comments No comments
{count} votes

Accepted answer
  1. AgaveJoe 28,291 Reputation points
    2021-06-04T21:49:11.293+00:00

    Not even the Id which holds the hash, this is so Mickey Mouse.

    The userId (sub) is in the claims collection.

    @page "/getuser"  
    @inject AuthenticationStateProvider authProvider  
    @attribute [Authorize]  
      
    <h3>GetUser</h3>  
      
    <div>  
        <ul>  
            @foreach (var claim in authState.User.Claims)  
            {  
                <li><b>@claim.Type</b>: @claim.Value</li>  
            }  
        </ul>  
    </div>  
      
    <div>  
        UserId = @(userId ?? "No sub found!")  
    </div>  
    @code {  
        private Models.WeatherForecast[] forecasts;  
        AuthenticationState authState;  
        private string userId;  
      
        protected override async Task OnInitializedAsync()  
        {  
            authState = await authProvider.GetAuthenticationStateAsync();  
            userId = authState.User.Claims.FirstOrDefault(c => c.Type == "sub").Value;  
        }  
    }  
    

    And since we are on the subject, I was expecting all the razor pages necessary to do CRUD against this Identity db to be available for me to use. I only have Login, Logout and Register. Where is the rest?

    The identity server project contains the account related data and UI. If I recall it's the standard Identity Razor Page Class. Scaffold the pages you want if you need make changes to the code or just view the code. It might be a good idea to create a test project and scaffold Identity. I'm not sure if scaffold pages contains the CRUD you're looking for but the default Identity configuration exposes all the APIs. For example, adding a role to the Roles table. You'll have to write the UI bits yourself but the RoleManager API has everything you need to create and fetch roles from the DB.

    It is up to you to write code if you want to manage accounts from the Blazor application. That UI does have account maintenance logic which makes sense because Identity Server manages accounts. Someone might have created a GitHub repo. Just do an internet search. You might get lucky. To roll your own, host Web API on the Identity Server then expose the logic via Web API. Copy Razor Page code paste it into an API action. You're only interested in the data not the Razor Page UI.

    1 person found this answer helpful.
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Rena Ni - MSFT 2,066 Reputation points
    2021-06-03T01:43:24.42+00:00

    Hi @wavemaster ,

    As the document said:

    Additionally, again for security reasons, you must not use IHttpContextAccessor within Blazor apps. Blazor apps run outside of the context of the ASP.NET Core pipeline. The HttpContext isn't guaranteed to be available within the IHttpContextAccessor, nor is it guaranteed to be holding the context that started the Blazor app.

    For the workaround, you could refer to the github issue here:https://github.com/dotnet/aspnetcore/issues/22820#issuecomment-726068641


    If the answer is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best Regards,

    Rena


  2. AgaveJoe 28,291 Reputation points
    2021-06-04T18:37:02.83+00:00

    The following code assumes you are using the Identity Provider template. Inject the AuthenticationStateProvider service to get the AuthenticationState which contains the user.

    @page "/getuser"
    @inject AuthenticationStateProvider authProvider
    @attribute [Authorize]
    
    <h3>GetUser</h3>
    
    <div>
        Name = @Name
    </div>
    
    @code {
        private Models.WeatherForecast[] forecasts;
        private string Name;
    
        protected override async Task OnInitializedAsync()
        {
            AuthenticationState authState = await authProvider.GetAuthenticationStateAsync();
            Name = authState.User.Identity.Name;
        }
    }
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.