ASP.NET Core 2.2中AuthenticationFailedContext.Success()调用无效求助
问题分析与解决方案
你遇到的问题核心是:在OnAuthenticationFailed事件中完成refresh token验证并签发新令牌后,尽管调用了context.Success(),但认证中间件仍然返回403并终止请求管道——这是因为**OnAuthenticationFailed触发时,认证流程已经标记为失败,默认会生成错误响应结果,单纯调用Success()无法覆盖这个预设结果**。
解决方案:重置认证结果,让请求继续流转
在你成功验证refresh token并完成新令牌签发的代码分支中,除了设置context.Principal和调用context.Success(),还需要手动清除context.Result(它默认被赋值为错误响应),告诉认证中间件不要返回错误,而是继续将请求传递到后续的控制器逻辑。
修改你的AuthenticationFailed方法:
public static async Task AuthenticationFailed(this AuthenticationFailedContext context) { ILoggerFactory loggerFactory = context.HttpContext.RequestServices.GetService<ILoggerFactory>(); ILogger logger = loggerFactory.CreateLogger(nameof(JwtBearerExtensions)); string refreshToken = context.HttpContext.Request.Cookies[Defaults.RefreshTokenCookie]; if (string.IsNullOrEmpty(refreshToken)) { logger.LogWarning("No refresh token supplied with invalid JWT, Cookies are {0}", string.Join(", ", context.HttpContext.Request.Cookies.Keys)); return; } logger.LogInformation("Processing refresh token '{0}'.", refreshToken); IConfiguration configuration = context.HttpContext.RequestServices.GetService<IConfiguration>(); IUserService userService = context.HttpContext.RequestServices.GetService<IUserService>(); ITokenHandler handler = context.HttpContext.RequestServices.GetService<ITokenHandler>(); long? userId = await handler.ValidateRefreshToken(refreshToken); if (userId.HasValue) { User user = await userService.GetUserAsync(userId.Value); refreshToken = await handler.GenerateRefreshToken(userId.Value); string jwtToken = BuildJwtToken(user, configuration); context.HttpContext.Response.AddBearerAuthorization(jwtToken); context.HttpContext.Response.AddRefreshTokenCookie(refreshToken); context.Principal = new ClaimsPrincipal(BuildClaimsIdentity(user)); context.Success(); // 关键:清除错误结果,让请求继续向下流转 context.Result = new NoResult(); } }
为什么这样有效?
当JWT验证失败触发OnAuthenticationFailed时,JwtBearer中间件会默认将context.Result设置为一个错误响应(比如UnauthorizedResult),即使你调用context.Success()标记认证成功,中间件仍然会优先返回这个预设的错误结果。通过将context.Result设置为NoResult(),你告诉中间件“不需要返回任何响应,继续处理请求”,这样请求就会被传递到你的控制器方法,同时新的令牌和refresh token已经被添加到响应头和Cookie中。
额外注意事项
- 确保你的
BuildClaimsIdentity方法生成的ClaimsIdentity是有效的,并且包含后续授权所需的所有声明。 - 验证
AddBearerAuthorization和AddRefreshTokenCookie扩展方法是否正确设置了响应头和Cookie(比如Cookie的过期时间、SameSite属性等)。
内容的提问来源于stack exchange,提问作者helloserve
相关产品推荐
相关产品推荐

