You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 08:09:02