IdentityServer4中Windows身份验证失败时如何加载自定义登录页并避免浏览器弹窗
问题解答
疑问1:自定义登录页逻辑的注入位置
你当前的ProcessWindowsLoginAsync方法就是注入逻辑的合适位置,不需要额外修改其他中间件管道。
疑问2:感知Windows身份验证失败的逻辑
你首次调用AuthenticateAsync返回null是因为还没触发过Windows验证流程。当你返回Challenge后,浏览器会自动携带Kerberos/NTLM凭证重新请求当前接口,此时如果AuthenticateAsync仍然返回null,就说明Windows身份验证已经失败。
具体实现代码
你只需要修改原有方法的else分支,增加是否已经触发过验证的标记即可,修改后代码如下:
private async Task<IActionResult> ProcessWindowsLoginAsync(string returnUrl) { // 检查Windows验证是否已经请求且验证成功 var result = await HttpContext.AuthenticateAsync(_windowsAuthConfig.WindowsAuthenticationProviderName); if (result?.Principal is WindowsPrincipal wp) { // 原有验证成功的逻辑保持不变 var props = new AuthenticationProperties { RedirectUri = Url.Action("Callback"), Items = { { "returnUrl", returnUrl}, { "scheme", _windowsAuthConfig.WindowsAuthenticationProviderName} } }; var id = new ClaimsIdentity(_windowsAuthConfig.WindowsAuthenticationProviderName); var claims = await _userStore.GetClaimsForWindowsLoginAsync(wp); id.AddClaims(claims); _logger.LogDebug("使用Windows身份验证登录用户"); await HttpContext.SignInAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme,new ClaimsPrincipal(id),props); return Redirect(props.RedirectUri); } else { // 判断是否已经触发过一次Windows验证 if (!Request.Query.ContainsKey("windows_challenge_triggered")) { _logger.LogDebug("首次触发Windows身份验证"); // 给回调地址加触发标记,第二次请求即可识别为验证后回调 var challengeProps = new AuthenticationProperties { RedirectUri = Url.Action("ProcessWindowsLoginAsync", new { returnUrl, windows_challenge_triggered = true }) }; return Challenge(challengeProps, _windowsAuthConfig.WindowsAuthenticationSchemes); } else { _logger.LogDebug("Windows身份验证失败,跳转自定义登录页"); // 直接跳转到你实现的自定义登录页,携带returnUrl保证登录后能跳转回目标地址 return RedirectToAction("Login", "Account", new { returnUrl }); } } }
必要配置注意事项
- 请确保托管服务(IIS/Kestrel)开启了Windows验证,同时开启了匿名访问,否则验证请求会被服务器层直接拦截,无法走到你的业务逻辑判断分支
- 若使用IIS托管,需要在web.config的
aspNetCore节点配置forwardWindowsAuthToken="true",保证Windows验证令牌能正常传递到应用层 - 不要将Windows验证方案设置为全局默认验证方案,避免所有请求被强制触发Windows验证弹窗
内容的提问来源于stack exchange,提问作者nikhil
相关产品推荐
相关产品推荐

