I have a Blazor Server application and need to get the current user ID. Its easy to get the email and the user name, but not the ID. It was so easy in .net core 2.2. Why they did not expose the ID is beyond me. I am using .net core 5.0.
I've needed to do this recently, but in a newer Blazor Web App, using .Net 8.0, so thought I'd add my more recent example here.
I didn't want to copy/paste the same code into multiple pages, so came up with this:
Create the interface:
public interface IUserIdentityProcessor
{
Task<string?> GetCurrentUserId();
}
Create the class:
using Microsoft.AspNetCore.Components.Authorization;
public class UserIdentityProcessor : IUserIdentityProcessor
{
private readonly AuthenticationStateProvider _authenticationStateAsync;
public UserIdentityProcessor(AuthenticationStateProvider authenticationStateAsync)
{
this._authenticationStateAsync = authenticationStateAsync;
}
public async Task<string?> GetCurrentUserId()
{
var authstate = await this._authenticationStateAsync.GetAuthenticationStateAsync();
if (authstate == null)
{
return null;
}
var user = authstate.User;
return user.FindFirst(u => u.Type.Contains("nameidentifier"))?.Value;
}
}
Add the IoC line to your Program.cs:
builder.Services.AddScoped<IUserIdentityProcessor, UserIdentityProcessor>();
In your Blazor RazorComponent, add the using statement to the top of the page:
@inject IUserIdentityProcessor _userIdentityProcessor
...add this to your page load:
protected override async Task OnInitializedAsync()
{
var userId = this._userIdentityProcessor.GetCurrentUserId();
}
The result is a reusable class to get the user's Id (guid) and return it as a string. This can be called from a number of razor components/pages, and expanded to return more details from the user object, if needed.
There are a couple ways to do it. Here's one I found with a little hacking around. I like it because it only requires a single injection, and because ASP also handles roles. Surprisingly, "nameidentifier" is the UserId (which is a GUID) in a standard EF Core login:
@inject AuthenticationStateProvider _authenticationStateProvider
@code {
async Task<string> getUserId(){
var user = (await _authenticationStateProvider.GetAuthenticationStateAsync()).User;
var UserId = user.FindFirst(u => u.Type.Contains("nameidentifier"))?.Value;
return UserId;
}
}
I recommend in Visual Studio setting a break point after retrieving the user, and then hovering over it. That will allow you to inspect it and see all the little bits and pieces-- you'll be surprised how much neat information you can dig up in the User
object!
user.FindFirst(u => u.Type.Contains("sub"))?.Value
–
Patrickpatrilateral AuthenticationState
instead of injecting it on every component that uses it: learn.microsoft.com/en-us/aspnet/core/blazor/security/… –
Gyroplane The documentation indicates to use the Task<AuthenticationState>
approach instead of using AuthenticationStateProvider
directly since the component isn't notified automatically if the underlying authentication state data changes.
@code {
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
async Task<string> getUserName(){
var user = (await authenticationStateTask).User;
return user.Identity.Name;
}
async Task<string> getUserId(){
var user = (await authenticationStateTask).User;
var userid = user.FindFirst(u => u.Type.Contains("nameidentifier"))?.Value;
return userid;
}
}
I've needed to do this recently, but in a newer Blazor Web App, using .Net 8.0, so thought I'd add my more recent example here.
I didn't want to copy/paste the same code into multiple pages, so came up with this:
Create the interface:
public interface IUserIdentityProcessor
{
Task<string?> GetCurrentUserId();
}
Create the class:
using Microsoft.AspNetCore.Components.Authorization;
public class UserIdentityProcessor : IUserIdentityProcessor
{
private readonly AuthenticationStateProvider _authenticationStateAsync;
public UserIdentityProcessor(AuthenticationStateProvider authenticationStateAsync)
{
this._authenticationStateAsync = authenticationStateAsync;
}
public async Task<string?> GetCurrentUserId()
{
var authstate = await this._authenticationStateAsync.GetAuthenticationStateAsync();
if (authstate == null)
{
return null;
}
var user = authstate.User;
return user.FindFirst(u => u.Type.Contains("nameidentifier"))?.Value;
}
}
Add the IoC line to your Program.cs:
builder.Services.AddScoped<IUserIdentityProcessor, UserIdentityProcessor>();
In your Blazor RazorComponent, add the using statement to the top of the page:
@inject IUserIdentityProcessor _userIdentityProcessor
...add this to your page load:
protected override async Task OnInitializedAsync()
{
var userId = this._userIdentityProcessor.GetCurrentUserId();
}
The result is a reusable class to get the user's Id (guid) and return it as a string. This can be called from a number of razor components/pages, and expanded to return more details from the user object, if needed.
When you create a new Blazor Server project (.NET 8 & 9), you can select the option Auth: Individual Accounts, this will automatically create the authentication and authorization (login, registration, account management and deletion).
There is a class that is created
"IdentityUserAccessor.cs"
using Microsoft.AspNetCore.Identity;
namespace App.Components.Account
{
internal sealed class IdentityUserAccessor(UserManager<User> userManager, IdentityRedirectManager redirectManager)
{
public async Task<User> GetRequiredUserAsync(HttpContext context)
{
var user = await userManager.GetUserAsync(context.User);
if (user is null)
{
redirectManager.RedirectToWithStatus("Account/InvalidUser", $"Error: Unable to load user with ID '{userManager.GetUserId(context.User)}'.", context);
}
return user;
}
}
Component Usage Example:
@page "/Account/Manage/Disable2fa"
@using Microsoft.AspNetCore.Identity
@using App.Data
@inject UserManager<User> UserManager
@inject IdentityUserAccessor UserAccessor
@code {
private User user = default!;
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
protected override async Task OnInitializedAsync()
{
user = await UserAccessor.GetRequiredUserAsync(HttpContext);
if (HttpMethods.IsGet(HttpContext.Request.Method) && !await UserManager.GetTwoFactorEnabledAsync(user))
{
throw new InvalidOperationException("Cannot disable 2FA for user as it's not currently enabled.");
}
}
}
The User.cs model:
using App.Data.Models;
using Microsoft.AspNetCore.Identity;
namespace App.Data
{
// Add profile data for application users by adding properties to the User class
public class User : IdentityUser
{
}
}
© 2022 - 2024 — McMap. All rights reserved.