@page "/logout" @layout EmptyLayout @inject IJSRuntime JS @inject ILogger Logger @inject NavigationManager Navigation @inject AuthenticationStateProvider AuthStateProvider @inject HttpService HttpService @using System.Text.Json @code { protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) return; try { // 如果运行在浏览器 (WASM),直接调用后端 API 并清除 localStorage / provider if (OperatingSystem.IsBrowser()) { Logger.LogInformation("WASM logout: call API and clear local storage"); try { await HttpService.Post>("/api/sign/out", null); } catch { /* 忽略网络错误,仍继续清理客户端状态 */ } if (AuthStateProvider is PersistentAuthenticationStateProvider provider) { await provider.MarkUserAsLoggedOut(); } Navigation.NavigateTo("/account/login"); } else { // Server 模式:通过浏览器 fetch 发起带凭据的请求以便浏览器接收并删除 Cookie,然后强制重载 Logger.LogInformation("Server logout: use browser fetch to call /api/sign/out"); var jsResult = await JS.InvokeAsync("__atomx_post_json", "/api/sign/out", (object?)null); // 尝试解析返回,忽略细节 var success = jsResult.ValueKind == JsonValueKind.Object && jsResult.TryGetProperty("success", out var sp) && sp.GetBoolean(); Logger.LogInformation("Server logout result: {Success}", success); try { // 清理 localStorage(如果有的话) await localStorage.RemoveItemAsync(StorageKeys.AccessToken); await localStorage.RemoveItemAsync(StorageKeys.RefreshToken); } catch { } // 尽管我们可能已经处理了服务器态,强制重新加载确保 Circuit 更新 Navigation.NavigateTo("/account/login", forceLoad: true); } } catch (Exception ex) { Logger.LogWarning(ex, "Logout failed but proceeding to login page"); Navigation.NavigateTo("/account/login", forceLoad: true); } } } @* 页面内 JS 辅助:用于在 Server 模式下从浏览器发起 POST 并携带凭证,使浏览器接收 Set-Cookie/删除 Cookie *@