_layout.cshtml注销按钮登出后未更新问题求助
问题原因及解决方案
问题根源
当你调用SignOutAsync后,当前请求的User.Identity.IsAuthenticated并不会立即变为false——因为请求的身份信息是在请求开始时就基于传入的Cookie解析完成的,SignOutAsync只是在响应中告诉浏览器清除认证Cookie,并不会修改当前请求已有的User对象。所以直接返回Logout视图时,布局页使用的还是当前请求的认证状态,依然显示注销按钮;而重定向到Home是发起新请求,浏览器会带着更新后的Cookie(已清除认证信息),新请求的User状态为未认证,因此能正常显示登录按钮。
修复步骤
1. 修正前端注销按钮的提交方式
当前代码里的<a>标签直接发起GET请求,既没有提交表单(导致AntiForgeryToken无效),也不符合HTTP规范(注销是修改状态的操作,应该用POST)。把注销按钮改成表单提交:
@if (User.Identity.IsAuthenticated) { @using (Html.BeginForm("Logout", "Account", new { area = "" }, FormMethod.Post, new { id = "logoutForm" })) { @Html.AntiForgeryToken() <li class="nav-item"> <button type="submit" class="nav-link text-dark border-0 bg-transparent">Logout</button> </li> } } else { <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Account" asp-action="Login">Login</a> </li> }
2. 拆分后端Logout方法
把注销逻辑和显示注销页面的逻辑分开,用POST执行注销,完成后重定向到GET的Logout页面(新请求会使用更新后的Cookie状态):
// 处理注销逻辑的POST接口 [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); // 注销完成后重定向到GET的Logout页面 return RedirectToAction(nameof(Logout)); } // 显示注销成功页面的GET接口 [HttpGet] [AllowAnonymous] public IActionResult Logout() { // 这里的User是新请求的身份信息,已注销状态下会显示登录按钮 return View(); }
为什么这样能解决问题
POST接口执行注销后,通过RedirectToAction发起新的GET请求,浏览器会携带清除认证信息后的Cookie。新请求的User.Identity.IsAuthenticated会变为false,布局页的条件判断就能正确显示登录按钮,同时也符合HTTP安全规范(避免GET请求触发注销的CSRF风险)。
内容的提问来源于stack exchange,提问作者Stephan
相关产品推荐
相关产品推荐

