Reputation: 89
Custom message handler
It is expected to be logged out if the token cannot be renewed.
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
await SetAuthorizationHeader(request);
var response = await base.SendAsync(request, cancellationToken);
if (IsRefreshRequired(response))
{
var tokenRefreshed = await _authService.TryRefreshTokenAsync();
if (tokenRefreshed)
{
await SetAuthorizationHeader(request);
return await base.SendAsync(request, cancellationToken);
}
await _authService.LogoutAsync();
_navigationManager.NavigateTo(Routes.App.Login);
}
return response;
}
private async Task SetAuthorizationHeader(HttpRequestMessage request)
{
var accessToken = await _localStorage.GetItemAsync<string>(Auth.AccessToken);
if (!string.IsNullOrWhiteSpace(accessToken))
{
request.Headers.Authorization = new AuthenticationHeaderValue(Auth.Scheme, accessToken);
}
}
Authentication service
public async Task LogoutAsync()
{
await RemoveTokensAsync();
AuthStateProvider.NotifyAuthenticationStateChanged();
}
Custom authentication state provider
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var accessToken = await _localStorage.GetItemAsync<string>(Auth.AccessToken);
if (string.IsNullOrWhiteSpace(accessToken))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
var claims = TokenParser.ParseClaims(accessToken);
var user = new ClaimsPrincipal(new ClaimsIdentity(claims, Auth.AuthType));
return new AuthenticationState(user);
}
public void NotifyAuthenticationStateChanged()
{
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
After calling LogoutAsync
method, it successfully redirects me to the Login page, but it does not update the header:
If I will update the page or I will call LogoutAsync
not from handler but from razor component all will work:
Also it does not depend on http client I am using.
Upvotes: 0
Views: 1144
Reputation: 89
Based on the comments. Thanks @enet and @HenkHolterman.
Root cause: The StateHasChanged()
logic does not propagate 'out and up'. The logout is caused by a call on an inner component, the LoginDisplay component is not involved in the default updating.
Solution: UI rerender. There is no single way how to do it.
In my case I changed
_navigationManager.NavigateTo(Routes.App.Login);
to
_navigationManager.NavigateTo(Routes.App.Logout);
As result logout page triggers changing authentication state logic on component level and then redirects user to the login page.
Other way to do it -- define an event handler in message handler which should be triggered from within the LogoutAsync, after the call to NotifyAuthenticationStateChanged. The subscriber to this event should be the MainLayout component, which re-renders.
Upvotes: 1