ASP.NET Core中Negotiate认证带Cookie回退的配置问题
解决方案
方案1:使用内置策略认证方案(无需自定义授权处理程序)
这是ASP.NET Core原生支持的推荐方案,专门用于多认证方案的动态选择与自动回退场景,无需编写自定义授权处理逻辑,配置代码如下:
var builder = WebApplication.CreateBuilder(args); // 注册认证服务 builder.Services.AddAuthentication(options => { // 统一使用自定义混合策略作为所有认证流程的默认方案 options.DefaultScheme = "MixedAuth"; options.DefaultChallengeScheme = "MixedAuth"; }) // 注册Negotiate认证方案 .AddNegotiate() // 注册Cookie认证方案,配置常规参数 .AddCookie(options => { options.LoginPath = "/Account/Login"; options.AccessDeniedPath = "/Account/AccessDenied"; options.ExpireTimeSpan = TimeSpan.FromDays(7); }) // 注册混合认证策略方案 .AddPolicyScheme("MixedAuth", "混合认证策略", options => { // 认证流程选择逻辑:有Negotiate请求头时优先走Negotiate认证,否则走Cookie认证 options.ForwardDefaultSelector = context => { var authHeader = context.Request.Headers.Authorization.FirstOrDefault(); if (authHeader?.StartsWith("Negotiate ", StringComparison.OrdinalIgnoreCase) == true) { return "Negotiate"; } return "Cookie"; }; // 质询流程选择逻辑:首次质询先尝试Negotiate,失败后自动回退到Cookie options.ForwardChallengeSelector = context => { if (!context.Items.ContainsKey("NegotiateChallenged")) { context.Items["NegotiateChallenged"] = true; return "Negotiate"; } return "Cookie"; }; }); // 后续注册其他服务、中间件配置保持常规写法即可 builder.Services.AddAuthorization(); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); // 其他中间件配置... app.Run();
逻辑说明
- 首次访问受保护资源时,系统会先返回
WWW-Authenticate: Negotiate的质询头,域内客户端会自动携带Windows认证信息完成认证,全程无用户交互 - 若客户端不支持Negotiate认证(如非域设备、外网访问),Negotiate认证失败后会自动触发Cookie认证的质询,跳转到Cookie体系的登录页
- 完全替代自定义授权处理程序逻辑,无需额外处理认证优先级问题
方案2:修复现有自定义授权处理程序的逻辑
如果你需要保留自定义授权处理程序的结构,可修复代码中的参数错误,依次尝试两个认证方案即可:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext authorizationContext, AccessRequirement requirement) { var httpContext = _httpContextAccessor.HttpContext; var identity = authorizationContext.User.Identity; if (!identity.IsAuthenticated) { // 先尝试Negotiate认证 var negotiateResult = await httpContext.AuthenticateAsync("Negotiate"); if (negotiateResult.Succeeded) { authorizationContext.User = negotiateResult.Principal; authorizationContext.Succeed(requirement); return; } // Negotiate失败后尝试Cookie认证 var cookieResult = await httpContext.AuthenticateAsync("Cookie"); if (cookieResult.Succeeded) { authorizationContext.User = cookieResult.Principal; authorizationContext.Succeed(requirement); return; } // 两个方案都认证失败则返回,触发后续质询流程 return; } authorizationContext.Succeed(requirement); }
注意
你之前代码中AuthenticateAsync({"Negotiate || Cookie"})的写法不符合官方API规范,无法实现同时尝试多个认证方案的效果,必须依次调用两个方案的认证方法。
内容的提问来源于stack exchange,提问作者Beltway
相关产品推荐
相关产品推荐

