I've implemented a user authorization in Blazor server using both local DB and Microsoft Azure.
- When a user authorizes using Microsoft Azure the authorization is persistent when changing Blazor pages.
- When a user authorizes using local DB the authorization is reset (GetAuthorizationState returns null). And my question is why?
I've a custom CustomAuthenticationStateProvider:
public class CustomAuthenticationStateProvider : AuthenticationStateProvider{ private readonly IHttpContextAccessor _httpContextAccessor; public CustomAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public override Task<AuthenticationState> GetAuthenticationStateAsync() { var principal = _httpContextAccessor.HttpContext?.User; if (principal?.Identity?.IsAuthenticated != true) { principal = new ClaimsPrincipal(new ClaimsIdentity()); } return Task.FromResult(new AuthenticationState(principal)); } public void MarkUserAsAuthenticated(ClaimsPrincipal user) { NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user))); } public void MarkUserAsLoggedOut() { var principal = _httpContextAccessor.HttpContext?.User; NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal))); }}
In my Program.cs i have the azure authentication setup as follow:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApp( options => { options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.AccessDeniedPath = "/accessdenied"; //builder.Configuration.GetSection("AzureAd") builder.Configuration.Bind("AzureAD", options); options.Events ??= new OpenIdConnectEvents(); options.Events.OnTokenValidated = async context => { var identity = (ClaimsIdentity)context.Principal.Identity; var email = identity.Name; var repository = new UsersRepository(new SqlConnectionFactory(builder.Configuration.GetConnectionString("SuperSecretConnectionString"))); var roles = await repository.GetUserRolesAsync(email); foreach (var role in roles) { identity.AddClaim(new Claim(ClaimTypes.Role, role)); } }; });
And here is my code that authenticates user when he is logging in using the local DB (email and password)
public async Task SignInUserAsync(object user){ List<string> roles = await _usersRepository.GetUserRolesAsync(user.Email); var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.Name), // Use the actual name from the user model new Claim(ClaimTypes.Email, user.Email), // Use the actual email from the user model }; foreach (var role in roles) { var roleClaim = new Claim(ClaimTypes.Role, role); claims.Add(roleClaim); // Add each role claim } var identity = new ClaimsIdentity(claims, /*Explicit*/CookieAuthenticationDefaults.AuthenticationScheme); var principal = new ClaimsPrincipal(identity); ((CustomAuthenticationStateProvider)AuthenticationStateProvider).MarkUserAsAuthenticated(principal);}
Thank you for any input!