Reputation: 197
[https://code-maze.com/how-to-secure-blazor-webassembly-with-identityserver4/]
[https://github.com/Blazored/LocalStorage]
I have a Blazor WASM utilising IdentityServer4 (above guide) which use local storage as well.
In my "RemoteAuthenticatorView", I have hooked both OnLogInSucceeded & OnLogOutSucceeded events. The respective events will perform SetItemAsync & ClearAsync with local storage where there are some extra user details. User details is for the purpose of doing some minor data retrieval if required.
There are 2 issues right now
<RemoteAuthenticatorView Action="@Action" OnLogInSucceeded="SetClaimsPrincipalData" OnLogOutSucceeded="ClearClaimsPrincipalData">
</RemoteAuthenticatorView>
private async Task SetClaimsPrincipalData()
{
try
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
var loggedInAccount = UserData.GetClaimsValue(user);
var loggedInAccountStr = JsonHelper.SerializeString(loggedInAccount);
await this.localStorage.ClearAsync();
await this.localStorage.SetItemAsync(DisplayConfigs.SessionStorageKeyUserData, loggedInAccountStr);
}
}
catch (Exception ex)
{
}
}
private async Task ClearClaimsPrincipalData()
{
try
{
await this.localStorage.ClearAsync();
}
catch (Exception ex)
{
}
}
//=====//
protected override async Task OnInitializedAsync()
{
try
{
var savedUserDataString = await this.localStorage.GetItemAsync<string>(KeyUserData);
this.loggedInAccount = JsonHelper.DeserializeString<LoggedInAccount>(savedUserDataString);
//// Base init
await base.OnInitializedAsync();
}
catch (Exception ex)
{
logger.Error(ex, ex.Message);
}
finally
{
this.StateHasChanged();
}
}
Upvotes: 1
Views: 793
Reputation: 4941
Whenever I run into a race condition with local or session storage I end up making a service that holds/accesses the data. The service uses a bool flag isInitialized
and instead of directly accessing the storage I wait for the flag to be true
before reading the data.
public bool isInitialized = false;
public async Task SetClaimsPrincipalData()
{
// Set LocalStorage
// .
// .
// .
isInitialized = true;
}
public async Task<string> GetClaimsPrincipalData()
{
while (!isInitialized) { await Task.Delay(100); }
return await this.localStorage.GetAsync<string>(DisplayConfigs.SessionStorageKeyUserData);
}
Now when you call GetClaimsPrincipalData
it must wait for SetClaimsPrincipalData
to be completed before returning.
Upvotes: 3