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

WS-Federation Azure AD代理流程:获取原始Token为空问题求助

解决Azure AD WS-Federation + Cookie认证下On-Behalf-Of流程中OriginalToken为Null的问题

我之前也遇到过类似的困扰——在WS-Federation结合Cookie认证的架构里,默认配置不会把原始Token留存下来,直接导致OBO流程因为拿不到originalToken而失败。下面是我亲测有效的解决步骤:

1. 让WS-Federation中间件保存原始Token

WS-Federation中间件默认不会把Azure AD返回的原始断言(比如SAML 1.1或JWT)存储到HttpContext里,你需要在配置中间件时显式开启SaveTokens选项:

services.AddAuthentication(WsFederationDefaults.AuthenticationScheme)
    .AddWsFederation(options =>
    {
        options.Wtrealm = Configuration["AzureAd:Wtrealm"];
        options.MetadataAddress = Configuration["AzureAd:MetadataAddress"];
        // 关键配置:将原始Token保存到AuthenticationProperties中
        options.SaveTokens = true;
    });

2. 从HttpContext中正确提取原始Token

开启SaveTokens后,原始Token会被存在认证属性里。你可以通过以下代码获取:

// 先获取当前的认证结果
var authResult = await HttpContext.AuthenticateAsync(WsFederationDefaults.AuthenticationScheme);
if (!authResult.Succeeded)
{
    // 处理认证失败的情况,比如用户未登录
    return Unauthorized();
}

// 提取原始Token——注意WS-Federation默认返回的是id_token(SAML断言),如果是访问API的token可能是access_token
var originalToken = authResult.Properties.GetTokenValue("id_token");

// 不确定的话,可以遍历所有存储的Token类型,确认哪个是你需要的
foreach (var token in authResult.Properties.GetTokens())
{
    Debug.WriteLine($"Token类型:{token.Name},值:{token.Value}");
}

3. 确保Cookie认证中间件也保留Token

因为你同时使用Cookie认证,需要确保Cookie中间件也会把这些Token保存到Cookie的属性中,这样后续请求才能从Cookie里拿到Token:

services.AddCookie(options =>
{
    options.SaveTokens = true;
    // 其他Cookie相关配置(比如过期时间、路径等)
});

4. 正确创建UserAssertion

拿到originalToken后,要根据Token的类型选择对应的断言类型:

  • 如果是SAML 1.1断言,使用urn:oasis:names:tc:SAML:1.0:assertion作为类型
  • 如果是JWT Token,使用urn:ietf:params:oauth:grant-type:jwt-bearer作为类型

示例代码:

// 假设拿到的是SAML断言
var userAssertion = new UserAssertion(originalToken, "urn:oasis:names:tc:SAML:1.0:assertion");

// 之后就可以用这个断言调用Azure AD的OBO流程获取目标API的Token
var tokenRequest = new ClientCredentialsTokenRequest
{
    Address = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
    ClientId = webAppClientId,
    ClientSecret = webAppClientSecret,
    GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer",
    Assertion = userAssertion.Assertion,
    Scope = "api://target-api-client-id/.default"
};

var tokenResponse = await httpClient.RequestClientCredentialsTokenAsync(tokenRequest);

额外排查点

  • 确认Azure AD应用注册配置:你的Web应用必须拥有目标Web API的Delegated权限,并且已经获得管理员同意
  • 验证用户状态:确保HttpContext.User.Identity.IsAuthenticated为true,即用户已经完成WS-Federation认证
  • 检查Token有效期:如果原始Token已过期,OBO流程会失败,但当前问题是Token为null,所以先确保能成功提取到Token

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:25:32