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

.NET Core C# Web API调用Graph API返回401未授权问题如何解决

问题根因梳理

你的401错误根本不是调用Graph API触发的,是调用你自己的.NET Web API时就触发了,核心错误点有4个:

  • 令牌受众不匹配:你前端当前调用acquireTokenSilent获取的是Graph API的访问令牌,该令牌的aud(受众)声明为graph.microsoft.com,完全无法用于验证你自己的.NET Web API,API的JWT验证模块会直接拒绝该令牌返回401
  • 身份验证信息传递错误:你把令牌塞进了请求体,而.NET Web API的JWT验证默认从Authorization请求头提取Bearer令牌,根本获取不到可用于验证的令牌,直接触发401
  • 用法冗余:你已经配置了Microsoft.Identity.Web的On-Behalf-Of流能力,完全不需要前端获取Graph令牌再传给后端,后端可以自行兑换Graph的访问令牌
  • 参数绑定错误:前端提交的是FormData格式数据,后端接口用[FromBody]接收JSON格式参数,参数绑定失败也会触发权限验证前置的4xx错误

解决步骤

1. 调整前端MSAL配置和请求逻辑

首先在Azure门户的Web API应用注册中,暴露API并新增作用域,示例为api://<你的Web API Client ID>/access_as_user,再调整前端代码:

if (!graphData && inProgress === InteractionStatus.None) {
  // 这里请求的scope改为你自己Web API暴露的作用域,不再请求Graph的scope
  const apiAccessTokenRequest = {
    scopes: ["api://<你的Web API客户端ID>/access_as_user"]
  }
  instance.acquireTokenSilent(apiAccessTokenRequest).then((accessTokenResponse) => {
    const apiAccessToken = accessTokenResponse.accessToken;
    // 调用Web API时把令牌放到Authorization请求头,不需要再往请求体塞access_token
    fetch('/api/profile', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiAccessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ /* 你要传递的其他业务参数 */ })
    })
  }).catch((error) => {
    console.log(error);
  })
}

2. 调整后端配置和接口逻辑

首先确认appsettings.json配置正确:

"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "TenantId": "<你的租户ID>",
  "ClientId": "<你的Web API的客户端ID>",
  "ClientSecret": "<你的Web API的客户端密钥>"
},
"DownstreamApi": {
  "BaseUrl": "https://graph.microsoft.com/v1.0",
  "Scopes": "User.Read" // 替换为你实际需要的Graph作用域
}

再调整ProfileController代码,你注入的GraphServiceClient已经由Microsoft.Identity.Web自动处理On-Behalf-Of流兑换令牌,不需要自己加授权头:

[Authorize] // 必须加Authorize特性触发身份验证
[HttpPost]
public async Task<ActionResult> PostProfileItem([FromBody] 你的业务参数DTO dto)
{
    HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
    try
    {
        User profile = await _graphServiceClient.Me.Request().GetAsync();
        return Ok(profile);
    }
    catch (Exception ex)
    {
        return StatusCode(500, ex.Message);
    }
}

你原来的SetProfileDTO可以直接删除,不需要接收前端传递的access_token。

3. 验证Azure应用注册配置

  • 确认前端应用注册的API权限列表中,已经添加了你Web API暴露的作用域,且已经授予管理员同意
  • 确认Web API应用注册的API权限列表中,已经添加了需要的Graph权限,且已经授予管理员同意
  • 确认Web API应用注册的「已知客户端应用」列表中,添加了前端应用的客户端ID,避免授权同意提示问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 09:09:03