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

ADFS OnBehalfOf令牌缺失sub声明问题排查求助

问题:MSAL结合ADFS2019获取的On-Behalf-Of令牌缺失用户声明

场景说明

使用MSAL结合ADFS2019实现Web应用代表已认证用户调用内部API,初始获取的访问令牌包含完整用户标识声明,但调用AcquireTokenOnBehalfOf返回的下游API令牌仅包含应用相关信息,缺失sub、email等用户声明。

初始访问令牌内容(含用户声明)

{
  "aud": "https://SRV",
  "iss": "[***REMOVED***]",
  "iat": 1687181262,
  "nbf": 1687181262,
  "exp": 1687184862,
  "email": "user1@mydomain.com",
  "winaccountname": "user1@mydomain.com",
  "anchor": "sub",
  "sub": "user1@mydomain.com",
  "apptype": "Confidential",
  "appid": "https://SRV",
  "authmethod": "http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows",
  "auth_time": "2023-06-19T12:11:56.653Z",
  "ver": "1.0",
  "scp": "email user_impersonation profile openid"
}

下游API访问令牌内容(缺失用户声明)

{
  "aud": "api://API",
  "iss": "[***REMOVED***]",
  "iat": 1687181215,
  "nbf": 1687181215,
  "exp": 1687184815,
  "apptype": "Confidential",
  "appid": "https://SRV",
  "auth_time": "2023-06-19T12:11:56.653Z",
  "authmethod": "http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows",
  "ver": "1.0",
  "scp": "profile user_impersonation openid email"
}

代码实现

var token = await HttpContext.GetTokenAsync("access_token");
var resource = _configuration["ADFS:Resource"];

var client = ConfidentialClientApplicationBuilder.Create(_configuration["ADFS:ClientID"]).
            WithAdfsAuthority(_configuration["ADFS:Instance"]).
            WithClientSecret(_configuration["ADFS:ClientSecret"]).Build();
var userAssertion = new UserAssertion(token, "urn:ietf:params:oauth:grant-type:jwt-bearer");
var result = await client.AcquireTokenOnBehalfOf(new[] { $"{resource}/openid", $"{resource}/email" , $"{resource}/user_impersonation" }, userAssertion)
            .WithClaims("sub, upn")
            .ExecuteAsync();

var httpClient = _httpClientFactory.CreateClient("WebAPI");
httpClient.BaseAddress = new Uri(_configuration["ServiceUrl"]);
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", result.AccessToken);
Weather = await httpClient.GetFromJsonAsync<IEnumerable<WeatherServiceResponse>>("/WeatherForecast");

return;

问题解决要点

  • ADFS API应用声明规则配置:ADFS不会自动传递用户声明到下游API,需在ADFS管理控制台中为api://API对应的应用添加声明规则:
    1. 找到目标API应用程序,进入声明规则页面
    2. 添加发送LDAP属性作为声明规则,将用户的sub、email等属性映射到令牌声明;或使用自定义规则确保声明传递
  • 修正WithClaims参数格式:当前传入的逗号分隔字符串不符合ADFS要求,需改为JSON格式的声明请求:
    .WithClaims("{\"access_token\":{\"sub\":null,\"email\":null}}")
    
    或使用ClaimsRequest类构建规范请求:
    var claimsRequest = new ClaimsRequest();
    claimsRequest.AddClaim("sub", null, "access_token");
    claimsRequest.AddClaim("email", null, "access_token");
    .WithClaims(claimsRequest)
    
  • 验证资源范围配置:确认请求的{resource}/openid等范围已在ADFS中为API应用正确配置,且允许传递用户声明
  • 匹配令牌受众:确保aud字段api://API与目标API的标识符完全一致,ADFS会根据受众筛选生效的声明规则

内容的提问来源于stack exchange,提问作者mberube.Net

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:35:18