如何从 Blazor 服务器端应用程序成功注销?
How to sign out successfully from a Blazor server-side app?
我正在通过执行以下操作注销:
public class LogoutModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
RedirectUri = redirectUri,
});
}
}
注销应该有效,因为我被重定向到正确的页面,在该页面中我有 link 返回主页:
<p class="mb-1">
@{
var url = $"{navigationManager.BaseUri}";
<NavLink class="nav-link" href=@($"{url}") Match="NavLinkMatch.Prefix">
Login again
</NavLink>
}
</p>
剃须刀页面如下:
<AuthorizeView>
<Authorized>
@{
navigationManager.NavigateTo("Main", forceLoad: true);
}
</Authorized>
<NotAuthorized>
@{
var returnUrl = $"{navigationManager.BaseUri}{options.LoginCallbackUrl}";
navigationManager.NavigateTo($"Login?redirectUri={returnUrl}", forceLoad: true);
}
</NotAuthorized>
</AuthorizeView>
在这个阶段,Authorized
标签内的代码被执行,我立即被重定向到主页。这不应该发生。
Startup.cs
中的OpenId设置为:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
为什么应用程序仍然认为用户仍然被授权?我错过了一步吗?
您必须在主布局上获取身份验证状态 - 生命周期事件 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);
}
}
请记住 Blazor 服务器端是 SPA 应用程序,这意味着页面永远不会重新加载,DOM 是通过服务器 <-> SignalR <-> Javascript 隧道更新的。
这意味着 cookie 身份验证只有在您强制重新加载页面时才有可能。
要了解如何处理身份验证(包括注销),请查看此示例。
https://github.com/iso8859/AspNetCoreAuthMultiLang
在AuthenticationStateProvider.GetAuthenticationStateAsync实现中你必须return空令牌
new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); = 未通过身份验证。
不需要子类化任何 类。解决问题的方法是先做:
public class LogoutModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
RedirectUri = redirectUri,
});
}
}
这将从 cookie 和 OpenId 中注销用户。要在此处导航,可以在剃须刀组件中执行以下操作:
@{
var returnUrl = $"{navigationManager.BaseUri}{LogoutCallbackUrl}";
<NavLink class="nav-link" href=@($"Logout?redirectUri={returnUrl}") Match="NavLinkMatch.Prefix" />
}
其中 LogoutCallbackUrl
将是重定向的页面,注销已完成。
最后一步是确保注销回调重定向页面允许匿名访问。所以如果回调是一个剃须刀组件,这将通过添加以下内容来完成:
@attribute [Microsoft.AspNetCore.Authorization.AllowAnonymous]
我正在通过执行以下操作注销:
public class LogoutModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
RedirectUri = redirectUri,
});
}
}
注销应该有效,因为我被重定向到正确的页面,在该页面中我有 link 返回主页:
<p class="mb-1">
@{
var url = $"{navigationManager.BaseUri}";
<NavLink class="nav-link" href=@($"{url}") Match="NavLinkMatch.Prefix">
Login again
</NavLink>
}
</p>
剃须刀页面如下:
<AuthorizeView>
<Authorized>
@{
navigationManager.NavigateTo("Main", forceLoad: true);
}
</Authorized>
<NotAuthorized>
@{
var returnUrl = $"{navigationManager.BaseUri}{options.LoginCallbackUrl}";
navigationManager.NavigateTo($"Login?redirectUri={returnUrl}", forceLoad: true);
}
</NotAuthorized>
</AuthorizeView>
在这个阶段,Authorized
标签内的代码被执行,我立即被重定向到主页。这不应该发生。
Startup.cs
中的OpenId设置为:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
为什么应用程序仍然认为用户仍然被授权?我错过了一步吗?
您必须在主布局上获取身份验证状态 - 生命周期事件 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);
}
}
请记住 Blazor 服务器端是 SPA 应用程序,这意味着页面永远不会重新加载,DOM 是通过服务器 <-> SignalR <-> Javascript 隧道更新的。 这意味着 cookie 身份验证只有在您强制重新加载页面时才有可能。
要了解如何处理身份验证(包括注销),请查看此示例。 https://github.com/iso8859/AspNetCoreAuthMultiLang
在AuthenticationStateProvider.GetAuthenticationStateAsync实现中你必须return空令牌
new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); = 未通过身份验证。
不需要子类化任何 类。解决问题的方法是先做:
public class LogoutModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
RedirectUri = redirectUri,
});
}
}
这将从 cookie 和 OpenId 中注销用户。要在此处导航,可以在剃须刀组件中执行以下操作:
@{
var returnUrl = $"{navigationManager.BaseUri}{LogoutCallbackUrl}";
<NavLink class="nav-link" href=@($"Logout?redirectUri={returnUrl}") Match="NavLinkMatch.Prefix" />
}
其中 LogoutCallbackUrl
将是重定向的页面,注销已完成。
最后一步是确保注销回调重定向页面允许匿名访问。所以如果回调是一个剃须刀组件,这将通过添加以下内容来完成:
@attribute [Microsoft.AspNetCore.Authorization.AllowAnonymous]