Search code examples
c#blazorasp.net-identity

How to get the userId of logged in user blazor server in CODE BEHIND or .CS file


I have retrieved the userId in a Blazor component using the code below: [CascadingParameter] public Task AuthenticationStateTask { get; set; }

protected override async Task OnInitializedAsync()
{
    YoogieContext cxt = new YoogieContext();
    var authState = await AuthenticationStateTask;  
    var user = authState.User;
    var UserStringId = user.FindFirst(c => c.Type.Contains("nameidentifier"))?.Value;
}

How do I get the userId from a code behind (.cs) file? Using Blazor Server.


Solution

  • Revised Answer

    The cascaded Task<AuthenticationStateTask> is derived from the AuthenticationStateProvider so you might as well use it in code behind classes. You have to use it in service classes, there's no cacaded value to access.

    The advantage of dropping back to the underlying AuthenticationStateProvider is you get access to the identity change events, so can react when the identity changes.

    Here's a simple service to demonstrate interacting with the AuthenticationStateProvider:

    public class MyIdentityService : IDisposable
    {
        private AuthenticationStateProvider _authenticationStateProvider;
    
        public event EventHandler<IdentityChangedEventArgs>? IdentityChanged;
    
        public MyIdentityService(AuthenticationStateProvider authenticationStateProvider)
        {
            // The dependancy container will inject it's AuthenticationStateProvider instance here
            _authenticationStateProvider = authenticationStateProvider;
            // register for the state changed event
            _authenticationStateProvider.AuthenticationStateChanged += NotifyIdentityChanged;
        }
    
        // Method to get the current Identity
        public async ValueTask<ClaimsPrincipal> GetCurrentIdentity()
        {
            AuthenticationState state = await _authenticationStateProvider.GetAuthenticationStateAsync();
            return state.User;
        }
    
        // Fire and forget async event handler that waits on the Task completion before invoking the Event
        private async void NotifyIdentityChanged(Task<AuthenticationState> newAuthStateTask)
        {
            AuthenticationState state = await newAuthStateTask;
            this.IdentityChanged?.Invoke(null, new() { Identity = state.User});
        }
    
        // de-register for the state changed event
        public void Dispose()
            => _authenticationStateProvider.AuthenticationStateChanged -= NotifyIdentityChanged;
    }
    
    // Custom Event Args class to pass the new identity
    public class IdentityChangedEventArgs : EventArgs
    {
        public ClaimsPrincipal Identity { get; init; } = new ClaimsPrincipal();
    }
    

    registered in Program:

    builder.Services.AddSingleton<WeatherForecastService>();
    builder.Services.AddScoped<MyIdentityService>();
    

    My Index.razor

    @page "/"
    
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    
    Welcome to your new app.
    
    <SurveyPrompt Title="How is Blazor working for you?" />
    
    <div class="alert alert-info">
        Identity 1: @(this.Identity1.Identity?.Name ?? "No User Logged In")
        </div>
    <div class="alert alert-success">
        Identity 2: @(this.Identity2.Identity?.Name ?? "No User Logged In")
    </div>
    

    And a code behind file that shows using the AuthenticationStateProvider directly and the MyIdentityService.

    public partial class Index : ComponentBase, IDisposable
    {
        private ClaimsPrincipal Identity1 = new ClaimsPrincipal();
        private ClaimsPrincipal Identity2 = new ClaimsPrincipal();
    
        [Inject] private AuthenticationStateProvider _authenticationStateProvider { get; set; } = default!;
        [Inject] private MyIdentityService _myService { get; set; } = default!;
    
        protected async override Task OnInitializedAsync()
        {
            AuthenticationState state = await _authenticationStateProvider.GetAuthenticationStateAsync();
            Identity1 = state.User;
            _authenticationStateProvider.AuthenticationStateChanged += OnAuthenticationStateChanged;
    
            Identity2 = await _myService.GetCurrentIdentity();
            this._myService.IdentityChanged += OnIdentityChanged;
        }
    
    
        private async void OnAuthenticationStateChanged(Task<AuthenticationState> newAuthStateTask)
        {
            AuthenticationState state = await newAuthStateTask;
            Identity1 = state.User;
            // if you want to update the component when the identity changes
            await this.InvokeAsync(StateHasChanged);
        }
    
        private async void OnIdentityChanged(object? sender, IdentityChangedEventArgs e)
        {
            Identity2 = e.Identity;
            // if you want to update the component when the identity changes
            await this.InvokeAsync(StateHasChanged);
        }
    
        public void Dispose()
        {
            _authenticationStateProvider.AuthenticationStateChanged -= OnAuthenticationStateChanged;
            this._myService.IdentityChanged -= OnIdentityChanged;
        }
    }
    

    Here's my test page - I've used Windows authentication for simplicity.

    enter image description here