Reputation: 7866
I trying to implement token base authentication in Blazor webassembly web application with Prerendering enabled.
The steps I have done so far:
It gives an error at AuthStateProvider
public class AuthStateProvider : AuthenticationStateProvider
{
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var token = await _localStorage.GetItemAsync<string>("authToken");
if (string.IsNullOrWhiteSpace(token))
return _anonymous;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(JwtParser.ParseClaimsFromJwt(token), "jwtAuthType")));
return _anonymous;
}
}
It gives an error
InvalidOperationException: JavaScript interop calls cannot be issued during server-side prerendering, because the page has not yet loaded in the browser. Prerendered components must wrap any JavaScript interop calls in conditional logic to ensure those interop calls are not attempted during prerendering.
at this line
var token = await _localStorage.GetItemAsync<string>("authToken");
Now that is obvious; this line should be wrapped in a condition to check for prerendering like:
public class AuthStateProvider : AuthenticationStateProvider
{
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var isNotPreRendering = this._httpContextAccessor.HttpContext.Response.HasStarted;
if(isNotPreRendering)
{
var token = await _localStorage.GetItemAsync<string>("authToken");
if (string.IsNullOrWhiteSpace(token))
return _anonymous;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(JwtParser.ParseClaimsFromJwt(token), "jwtAuthType")));
}
return _anonymous;
}
}
But the value of isNotPreRendering
always false. Is there any other way or work around to make it work?
Upvotes: 5
Views: 1665
Reputation: 164
I have fixed this issue in this way:
Once the app hits GetAuthenticationStateAsync() will find a try-catch, withing the catch I will return an AnonymousState.
AuthenticationState anonymousState = new(new ClaimsPrincipal(new ClaimsIdentity()));
try
{
var token = await _localStorageService.GetItemAsync<string>("authToken");
var memberId = await _localStorageService.GetItemAsync<int>("memberId");
if (string.IsNullOrEmpty(token) || memberId == 0)
return anonymousState;
_httpClient.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue("bearer", token);
var authState = new AuthenticationState(
new ClaimsPrincipal(
new ClaimsIdentity(JwtParser.ParseClaimFromJwt(token), "jwtAuthType")));
NotifyAuthenticationStateChanged(Task.FromResult(authState));
return authState;
}
catch
{
return await Task.FromResult(anonymousState);
}
In my MainLayout.cs I call the AuthenticationState again. This is not the cleanest solution but it does the work
Upvotes: 3