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

技术求助:如何通过ADFS作为身份提供商实现MS Office用户直接认证并解决适配问题

解决方案:让MS Office通过ADFS OIDC完成WebDAV认证

我来帮你拆解问题根源,再一步步给出具体的修复方案:

问题核心分析

你的思路方向是对的,但卡在了两个关键点:

  1. Office的嵌入式浏览器在处理MS-OFBA跳转时,不会自动携带之前的OpenIdConnect.nonce Cookie——这是Office内置浏览器的安全限制,导致ADFS收到请求时因为缺少nonce验证返回401,触发Windows凭证弹窗。
  2. 中间件的注册顺序和响应修改时机需要调整,才能确保OIDC挑战逻辑和Office兼容格式的响应正确衔接。

具体修复步骤

1. 调整中间件注册顺序(关键)

挑战触发逻辑必须在OIDC中间件之前执行,Office响应修改逻辑要在OIDC之后。正确的顺序如下:

// 第一步:触发OIDC挑战的中间件,放在最前面
app.Use(async (context, next) => {
    await next.Invoke();
    // 修正判断逻辑:仅对未认证的WebDAV请求触发挑战
    if (!context.Request.User.Identity.IsAuthenticated && IsWebDav(context.Request)) {
        context.Response.StatusCode = 401;
        context.Authentication.Challenge("ADFS");
    }
});

// 第二步:ADFS OIDC中间件,处理挑战生成跳转URL和nonce
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions("ADFS") {
    RedirectUri = "https://your-app-domain/signin-oidc", // 需和ADFS信赖方配置一致
    ResponseType = OpenIdConnectResponseType.IdToken,
    Authority = "https://adfs-provider.hostname/adfs",
    ClientId = "your-client-id",
    // 调整nonce Cookie配置,让Office浏览器能读取
    NonceCookie = new CookieAuthenticationOptions {
        HttpOnly = false,
        SecurePolicy = CookieSecurePolicy.Always,
        SameSite = SameSiteMode.None
    }
});

// 第三步:修改响应为Office兼容格式的中间件
app.Use(async (context, next) => {
    await next.Invoke();
    
    var provider = "ADFS";
    var challenge = context.Authentication.AuthenticationResponseChallenge;
    bool isAdfsChallenge = challenge != null 
        && challenge.AuthenticationTypes?.Any(at => string.Equals(at, provider, StringComparison.Ordinal)) == true;
    
    // 仅对OIDC生成的302跳转响应做修改
    if (isAdfsChallenge && context.Response.StatusCode == 302) {
        var loginUri = context.Response.Headers["Location"].ToString();
        var successUri = $"{context.Request.Scheme}://{context.Request.Host.ToUriComponent()}{context.Request.Path}";
        
        // 提取nonce并编码到loginUri中(绕过Cookie传递限制)
        var nonceValue = context.Request.Cookies.Keys
            .FirstOrDefault(k => k.StartsWith("OpenIdConnect.nonce."))?
            .Split('.')
            .Last();
        if (!string.IsNullOrEmpty(nonceValue)) {
            loginUri += loginUri.Contains('?') ? "&" : "?";
            loginUri += $"nonce={Uri.EscapeDataString(nonceValue)}";
        }
        
        // 重置响应为Office兼容的403格式
        context.Response.StatusCode = 403;
        context.Response.Headers.Clear();
        context.Response.Headers.Add("X-FORMS_BASED_AUTH_REQUIRED", new[] { $"{loginUri}?ReturnUrl={Uri.EscapeDataString(successUri)}" });
        context.Response.Headers.Add("X-FORMS_BASED_AUTH_RETURN_URL", new[] { successUri });
        context.Response.Headers.Add("X-FORMS_BASED_AUTH_DIALOG_SIZE", new[] { "800x600" });
    }
});

2. 配置ADFS接受查询参数中的nonce

默认ADFS只认可Cookie中的nonce,需要修改ADFS设置允许通过查询参数传递:

  • 通过ADFS管理控制台:进入服务 > 认证方法,找到OpenID Connect设置,启用"允许通过查询参数传递nonce"(ADFS 2019+支持)
  • 或者用PowerShell命令:
Set-AdfsProperties -EnableOidcNonceInQueryString $true

替代方案:改用WS-Federation协议

如果OIDC的nonce问题难以彻底解决,推荐切换到ADFS的WS-Federation协议——它的认证流程不需要nonce,更适配Office的OFBA机制:

  1. 注册WS-Federation中间件替代OIDC
  2. 触发挑战时,直接生成ADFS的WS-Fed登录URL,返回403+自定义头,Office就能直接加载ADFS的凭证页面,无需处理nonce问题。

额外注意事项

  • 确保ADFS的信赖方信任配置中,你的应用回调地址已被添加为允许的地址
  • 测试时用Fiddler监控完整请求链,确认nonce被正确传递到ADFS
  • 若Office仍无法加载ADFS页面,检查ADFS是否配置了SameSite=None的Cookie(跨域场景下需要)

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 14:02:31