Reputation: 16280
I'm logging out by doing the following:
public class LogoutModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
RedirectUri = redirectUri,
});
}
}
signing out should be working because I get redirected to the correct page in which I have a link to go back to the home page:
<p class="mb-1">
@{
var url = $"{navigationManager.BaseUri}";
<NavLink class="nav-link" href=@($"{url}") Match="NavLinkMatch.Prefix">
Login again
</NavLink>
}
</p>
The razor page is as follows:
<AuthorizeView>
<Authorized>
@{
navigationManager.NavigateTo("Main", forceLoad: true);
}
</Authorized>
<NotAuthorized>
@{
var returnUrl = $"{navigationManager.BaseUri}{options.LoginCallbackUrl}";
navigationManager.NavigateTo($"Login?redirectUri={returnUrl}", forceLoad: true);
}
</NotAuthorized>
</AuthorizeView>
At this stage, the code within the Authorized
tag gets executed and I get redirected immediately to the main page. Which should not happen.
The OpenId settings in Startup.cs
are:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
Why is the app still thinking that the user is still authorized? Am I missing a step?
Upvotes: 1
Views: 5470
Reputation: 16280
There is no need to subclass any classes. The way to solve the problem is by first doing:
public class LogoutModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
RedirectUri = redirectUri,
});
}
}
This will sign out the user from cookies and OpenId. To navigate here, one can do the following in a razor component:
@{
var returnUrl = $"{navigationManager.BaseUri}{LogoutCallbackUrl}";
<NavLink class="nav-link" href=@($"Logout?redirectUri={returnUrl}") Match="NavLinkMatch.Prefix" />
}
where LogoutCallbackUrl
will be the page for the redirect was sign out has completed.
The last step is to make sure that the logout callback redirect page allows for anonymous access. So if the callback is a razor component, this would be done by adding the following:
@attribute [Microsoft.AspNetCore.Authorization.AllowAnonymous]
Upvotes: 2
Reputation: 910
Keep in mind Blazor server side is SPA application, this mean the page is never reload, DOM is update with the server <-> SignalR <-> Javascript tunnel. This mean cookie authentication is only possible is you force page reload.
To understand how to handle authentication, including sign out, have a look at this example. https://github.com/iso8859/AspNetCoreAuthMultiLang
In AuthenticationStateProvider.GetAuthenticationStateAsync implementation you must return empty token
new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); = not authenticated.
Upvotes: 1
Reputation: 640
You have to get authentication state on main layout - lifecycle event OnInitialized{Async}.
protected override async Task OnInitializedAsync()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
User = authState.User;
if (!User.Identity.IsAuthenticated)
{
NavMan.NavigateTo("Identity/Account/Login", true);
}
}
Upvotes: 2