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

无法从受Azure AD保护的.NET Web API项目调用SharePoint Rest API

问题根因

你从请求头拿到的令牌是前端申请的、受众为你自有Web API的访问令牌,其aud声明为你Web API的Client ID,而SharePoint要求访问令牌的受众必须为SharePoint服务,所以直接调用必然返回401,确实需要单独申请面向SharePoint的访问令牌。

推荐方案

采用Azure AD的代理流(On-Behalf-Of, OBO),这是中间层Web API接收到用户令牌后,代表用户访问下游API的标准实现方案,不需要额外注册新的Azure AD应用,直接复用你现有Web API的注册信息即可。

具体操作步骤

1. 调整现有Azure AD应用配置

  • 进入你已注册的Azure AD应用管理页,打开「API权限」页,添加SharePoint Online的委托权限,根据你的业务需求选择对应权限(比如读取站点内容选Sites.Read.All,读写选Sites.ReadWrite.All),添加后点击「授予管理员同意」完成权限激活。
  • 进入「证书和密码」页,新建一个客户端密码,保存好密码值,后续配置需要用到。

2. 调整项目配置与依赖

  • 确保已安装NuGet包:Microsoft.Identity.Web、Microsoft.Identity.Web.TokenCache,注意.NET Core 3.1环境下请选择1.x版本的包,高版本不再兼容.NET Core 3.1。
  • 修改Startup.cs的身份验证配置,启用令牌获取能力和内存缓存:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(Configuration)
    // 启用下游API令牌获取能力
    .EnableTokenAcquisitionToCallDownstreamApi()
    // 添加内存令牌缓存,生产环境可替换为分布式缓存
    .AddInMemoryTokenCaches();
  • 修改appsettings.json的AzureAd节点,补充刚才生成的客户端密码:
"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "Domain": "mydomain.onmicrosoft.com",
  "ClientId": "你的Web API Client ID",
  "TenantId": "你的租户ID",
  "Audience": "你的Web API Client ID",
  "ClientSecret": "刚才生成的客户端密码",
  "AllowWebApiToBeAuthorizedByACL": true
}

3. 控制器内调用SharePoint REST API

在控制器中注入ITokenAcquisition服务,先申请面向SharePoint的访问令牌,再用新令牌发起请求即可,示例代码如下:

using Microsoft.Identity.Web;
using System.Net.Http.Headers;

[Route("api/v1/[controller]")]
[ApiController]
[Authorize]
public class SpController : ControllerBase
{
    private readonly ITokenAcquisition _tokenAcquisition;
    private readonly IHttpClientFactory _httpClientFactory;

    public SpController(ITokenAcquisition tokenAcquisition, IHttpClientFactory httpClientFactory)
    {
        _tokenAcquisition = tokenAcquisition;
        _httpClientFactory = httpClientFactory;
    }

    [HttpGet("get-site-info")]
    public async Task<IActionResult> GetSiteInfo()
    {
        // 替换为你的SharePoint站点域名和对应权限范围
        var spoScopes = new[] { "https://你的租户名.sharepoint.com/Sites.ReadWrite.All" };
        // 申请面向SharePoint的访问令牌
        var spoAccessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(spoScopes);

        var httpClient = _httpClientFactory.CreateClient();
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", spoAccessToken);

        // 替换为你实际要调用的SharePoint REST API地址
        var response = await httpClient.GetAsync("https://你的租户名.sharepoint.com/sites/你的站点名/_api/web");
        if (response.IsSuccessStatusCode)
        {
            var result = await response.Content.ReadAsStringAsync();
            return Ok(result);
        }
        return StatusCode((int)response.StatusCode, await response.Content.ReadAsStringAsync());
    }
}

注意事项

  • 前端申请你的Web API访问令牌时,scope必须填写你Web API暴露的权限标识,不能直接用SharePoint的scope。
  • 若调用时报权限不足错误,检查Azure AD应用的SharePoint权限是否已经完成管理员同意,权限范围是否匹配你要执行的操作。
  • 生产环境建议替换内存令牌缓存为分布式缓存(比如Redis),避免多实例部署时重复申请令牌。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:27:05