Get User information in Blazor IdentityServer

Amjad Khan 41 Reputation points
2022-06-29T01:00:15.393+00:00

I have a .NET6 Blazor wasm application that uses IdentityServer4 for authentication. I want to create a login event in database whenever a user logs in. To do that, I am using the IdentityServer
ClientAuthenticationSuccess
event as follows. The issue is that
user
is always null that I am getting from
HttpContextAccessor
:

   public class CustomEventSink : IEventSink  
       {  
           private readonly ApplicationDbContext _context;  
           private readonly IHttpContextAccessor _httpContextAccessor;  
           private readonly UserManager<ApplicationUser> _userManager;  
           public CustomEventSink(ApplicationDbContext context, UserManager<ApplicationUser> user, IHttpContextAccessor contextAccessor)  
           {  
                
               _context = context;  
               _httpContextAccessor = contextAccessor;  
               _userManager = user;  
           }  
     
           public async Task PersistAsync(Event evt)  
           {  
               //log event here....  
                 
               EventLog el = new();  
               if (@evt.Id.Equals(EventIds.ClientAuthenticationSuccess))  
               {  
                     
                   try  
                   {  
                       var user = await _userManager.GetUserAsync(_httpContextAccessor.HttpContext.User);  
                       if (user != null)  
                       {  
                           // do stuff  
                           el.EventName = "Login";  
                           el.EventDescription = $"{evt.Name} ({evt.Id}), Details:{evt}";  
                           el.Created = DateTime.Now;  
                           el.UserName = user.UserName;  
                           _context.EventLog.Add(el);  
                           _context.SaveChanges();  
     
                       }  
                         
                   }  
                   catch (Exception ex)  
                   {  
                       // handle exception  
                   }  
               }  
     
               if (@evt.Id.Equals(EventIds.ClientAuthenticationFailure))  
               {  
     
                   try  
                   {  
                         
                           // do stuff  
                           el.EventName = "Login Failure";  
                           el.EventDescription = $"{evt.Name} ({evt.Id}), Details:{evt}";  
                           el.Created = DateTime.Now;  
                           _context.EventLog.Add(el);  
                           _context.SaveChanges();  
     
                         
     
                   }  
                   catch (Exception ex)  
                   {  
                       // handle exception  
                   }  
               }  
     
           }  
       }  

The problem is that
user
is always null.

Startup.cs:

   namespace P.Server  
   {  
       public class Startup  
       {  
     
           public Startup(IConfiguration configuration)  
           {  
               Configuration = configuration;  
           }  
     
           public IConfiguration Configuration { get; }  
     
           // This method gets called by the runtime. Use this method to add services to the container.  
           // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
           public void ConfigureServices(IServiceCollection services)  
           {  
               //services.AddDbContext<ApplicationDbContext>(options =>  
               //    options.UseSqlServer(  
               //        Configuration.GetConnectionString("DefaultConnection")));  
               services.AddDatabaseDeveloperPageExceptionFilter();  
               services.AddSyncfusionBlazor();  
               services.AddDbContext<ApplicationDbContext>(options =>  
               options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), new MySqlServerVersion(new Version(8, 0, 26))));  
               services.AddOptions();  
               services.AddControllers();  
     
               services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)  
                   .AddRoles<IdentityRole>()  
                   .AddEntityFrameworkStores<ApplicationDbContext>();  
     
     
               services.AddIdentityServer(options =>  
                   {  
                       options.Events.RaiseSuccessEvents = true;  
                       options.Events.RaiseFailureEvents = true;  
                       options.Events.RaiseErrorEvents = true;  
                   })  
                   .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>  
                   {  
                       options.IdentityResources["openid"].UserClaims.Add("role");  
                       options.ApiResources.Single().UserClaims.Add("role");  
     
                   });  
     
     
               services.AddAuthentication()  
                   .AddIdentityServerJwt();  
                 
               services.AddAuthorization();  
               services.AddHttpContextAccessor();  
               services.AddSession();  
     
               //services.AddSingleton<IUserIdProvider, NameUserIdProvider>(); //this is for signalr  
     
               services.AddControllersWithViews();  
               services.AddRazorPages();  
               services.AddResponseCompression(opts =>  
               {  
                   opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(  
                       new[] { "application/octet-stream" });  
               });  
               services.Configure<IdentityOptions>(options =>  
               {  
                   // Password settings  
                   options.Password.RequireDigit = false;  
                   options.Password.RequiredLength = 4;  
                   options.Password.RequireNonAlphanumeric = false;  
                   options.Password.RequireUppercase = false;  
                   options.Password.RequireLowercase = false;  
     
               });  
               services.AddServerSideBlazor();  
               services.AddResponseCompression(opts =>  
               {  
                   opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(  
                       new[] { "application/octet-stream" });  
               });  
               services.AddMvc().AddMvcOptions(options =>  
               {  
                   options.EnableEndpointRouting = false;  
               });  
               services.AddMvcCore(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter()));  
               services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);  
               services.AddMvc().AddXmlDataContractSerializerFormatters();  
               services.AddSignalR();  
                 
               services.AddTransient<IEventSink, CustomEventSink>();  
     
               //services.AddCors(options =>  
               //{  
               //    options.AddPolicy("EnableCORS", builder =>  
               //    {  
               //        builder.AllowAnyOrigin().AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials().Build();  
               //    });  
               //});  
               //services.AddMvc(option => option.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);  
     
     
           }  
     
           // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
           public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)  
           {  
               app.UseResponseCompression();  
     
               if (env.IsDevelopment())  
               {  
                   app.UseDeveloperExceptionPage();  
                   app.UseMigrationsEndPoint();  
                   app.UseWebAssemblyDebugging();  
               }  
               else  
               {  
                   app.UseExceptionHandler("/Error");  
                   // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.  
                   app.UseHsts();  
               }  
     
               app.UseHttpsRedirection();  
               app.UseBlazorFrameworkFiles();  
               app.UseStaticFiles();  
     
               app.UseRouting();  
               app.UseSession();  
     
               app.UseIdentityServer();  
     
               app.UseAuthentication();  
               app.UseAuthorization();  
               app.UseEndpoints(endpoints =>  
               {  
                   endpoints.MapRazorPages();  
                   endpoints.MapControllers();  
                   endpoints.MapHub<Broadcaster>("/broadcaster");  
                   endpoints.MapHub<LoginCountHub>("/LoginCountHub");  
                   endpoints.MapFallbackToFile("index.html");  
               });  
               CreateRoles(serviceProvider).Wait();  
     
           }  
     
           ...  
     
     
     
     
       }  
   }  
Developer technologies | .NET | Blazor
{count} votes

1 answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2022-06-29T01:47:49.383+00:00

    In identity server User is set at the start of authentication. It will null if user is not authenticated at the start of the request. The user will not be set until the user makes another request to the login server, which typically would happen on a refresh token request.

    I believe you can get the name passed to event if you use identity server events.


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.