IIS共存JWT与Windows认证时JWT失效如何返回401而非登录弹窗
触发Windows认证流程的原因
- 你自定义的JWT认证处理器在令牌校验失败时返回了
AuthenticateResult.NoResult(),这个返回值的语义是当前处理器未找到对应认证凭据,将认证逻辑流转到后续注册的其他认证方案 - 你在IIS侧同时启用了Windows身份验证,ASP.NET Core授权中间件检测到JWT方案未返回成功认证结果后,会触发IIS内置的Windows认证模块的挑战逻辑,返回带
WWW-Authenticate: NTLM/Negotiate的响应头,浏览器收到后就会弹出Windows登录窗口 - 二次调用
HandleAuthenticateAsync是因为浏览器收到Windows认证挑战后,会自动携带本地Windows凭据重试请求,因此你的JWT处理器会被再次调用
实现JWT失败直接返回401的方案
方案1:修改自定义JWT处理器逻辑
将认证失败的返回值从AuthenticateResult.NoResult()改为AuthenticateResult.Fail(),同时重写挑战处理方法直接返回401,阻止认证逻辑流转到Windows方案:
public class BearerAuthenticationHandler : AuthenticationHandler<BearerAuthenticationSchemeOptions> { private IJwtUtils _jwtUtils; public BearerAuthenticationHandler( IOptionsMonitor<BearerAuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IJwtUtils jwtUtils) : base(options, logger, encoder, clock) { _jwtUtils = jwtUtils; } protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { var token = Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); var user = _jwtUtils.ValidateJwtToken(token); if (user != null) { var ticket = new AuthenticationTicket(user, this.Scheme.Name); return AuthenticateResult.Success(ticket); } // 认证失败直接返回Fail,不再流转到其他认证方案 return AuthenticateResult.Fail("无效或缺失JWT令牌"); } // 重写挑战方法,直接返回401,不触发Windows认证弹窗 protected override Task HandleChallengeAsync(AuthenticationProperties properties) { Response.StatusCode = 401; Response.ContentType = "application/json"; return Response.WriteAsync("{\"code\":401,\"message\":\"身份验证失败\"}"); } }
方案2:调整认证服务配置
显式指定所有认证相关的默认方案为JWT,禁止自动 fallback 到其他认证方案:
services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddScheme<BearerAuthenticationSchemeOptions, BearerAuthenticationHandler>(JwtBearerDefaults.AuthenticationScheme, null);
方案3(可选):调整IIS配置
如果不需要全局启用Windows认证,可在项目根目录的web.config中添加配置,让IIS不强制拦截未认证请求,所有认证逻辑交给ASP.NET Core代码处理:
<system.webServer> <security> <authentication> <windowsAuthentication enabled="true" /> <anonymousAuthentication enabled="true" /> </authentication> <authorization> <!-- 允许匿名访问,IIS不主动触发认证挑战 --> <add accessType="Allow" users="?" /> </authorization> </security> </system.webServer>
内容的提问来源于stack exchange,提问作者Семён Прокофьев
相关产品推荐
相关产品推荐

