Hi,
I used sessionStorage to ensure that the user remains logged in throughout the session. I had my own pre built database with usernames and passwords, so I did not use migrations and did not implement this with IdentityRevalidatingAuthenticationStateProvider. One issue I encounter with sessionStorage is that when I refresh the page, I use the Fluent UI library and I briefly see a "not authorized" text.
I am not sure if this is the correct usage, or if it is wrong, as I do not receive any error messages. On the homepage, I used amCharts for graphics, and when I refresh this page, I see the following message in the Visual Studio output: "Exception thrown:'Microsoft.JSInterop.JSDisconnectedException' in System.Private.CoreLib.dll". Still, the application runs.
Also, sometimes the application fails to open, and sometimes it does not. Could this intermittent failure be due to the use of localStorage or sessionStorage?
using BlazorApp4.Services;
using Blazored.SessionStorage;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
private ISessionStorageService _sessionStorage;
private IUserService _userService;
public CustomAuthenticationStateProvider(ISessionStorageService sessionStorage, IUserService userService)
{
_sessionStorage = sessionStorage;
_userService = userService;
}
//prerendering sırasında ya da kullanıcı bilgisi olmadığında anonim kimlik döndürür
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
return Task.FromResult(new AuthenticationState(anonymousUser));
}
public async Task LoadUserStateAsync()
{
var username = await _sessionStorage.GetItemAsStringAsync("username");
ClaimsIdentity identity;
if (!string.IsNullOrEmpty(username))
{
identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, "CustomAuthType");
}
else
{
identity = new ClaimsIdentity();
}
var user = new ClaimsPrincipal(identity);
var currentState = new AuthenticationState(user);
//var snapshot = new AuthenticationState(new ClaimsPrincipal(identity));
//await Task.Yield();
NotifyAuthenticationStateChanged(Task.FromResult(currentState));
}
//public async Task LoadUserStateAsync()
//{
// var username = await _sessionStorage.GetItemAsStringAsync("username");
// ClaimsIdentity identity = !string.IsNullOrEmpty(username)
// ? new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, "CustomAuthType")
// : new ClaimsIdentity();
// var user = new ClaimsPrincipal(identity);
// NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
//}
public async Task<bool> MarkUserAsAuthenticated(string username, string password)
{
var user = await _userService.ValidateUserCredentials(username, password);
if (user != null)
{
await _sessionStorage.SetItemAsStringAsync("username", username);
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username),
}, CookieAuthenticationDefaults.AuthenticationScheme);
var userPrincipal = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(userPrincipal)));
return true;
}
return false;
}
public async Task MarkUserAsLoggedOut()
{
await _sessionStorage.RemoveItemAsync("username");
var identity = new ClaimsIdentity();
var user = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
}
}
MainLayout:
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.FluentUI.AspNetCore.Components
@inherits LayoutComponentBase
@using FluentOrientation = Microsoft.FluentUI.AspNetCore.Components.Orientation;
@inject AuthenticationStateProvider AuthenticationStateProvider
<FluentLayout >
<FluentHeader>
Blazor App
</FluentHeader>
<CultureSelector />
<FluentStack Orientation="FluentOrientation.Horizontal" Width="100%">
<div>
<FluentNavMenu @bind-Expanded="@Expanded" Width="200" Collapsible="true" Title="App Navigation Menu">
<AuthorizeView>
<Authorized>
<FluentNavLink Href="/" Icon="@(new Icons.Regular.Size24.Home())">Anasayfa</FluentNavLink>
<FluentNavLink Href="personals" Icon="@(new Icons.Regular.Size24.People())">Personel Listesi</FluentNavLink>
<FluentNavLink Href="Account/Logout">Çıkış Yap</FluentNavLink>
</Authorized>
<NotAuthorized>
<FluentNavLink Href="Account/Login">Giriş Yap</FluentNavLink>
</NotAuthorized>
</AuthorizeView>
</FluentNavMenu>
</div>
<FluentBodyContent>
<div class="content">
@Body
</div>
</FluentBodyContent>
<FluentToastProvider @rendermode=@InteractiveServer />
<FluentDialogProvider @rendermode=@InteractiveServer />
<FluentTooltipProvider @rendermode=@InteractiveServer />
<FluentMessageBarProvider @rendermode=@InteractiveServer />
</FluentStack>
</FluentLayout>
@code
{
bool Expanded = true;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await ((CustomAuthenticationStateProvider)AuthenticationStateProvider).LoadUserStateAsync();
StateHasChanged();
}
}
}