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

如何通过Graph和Microsoft Identity Web为API同时配置应用与委托权限

问题描述

我正在开发的应用需要访问用户不一定具备权限的OneDrive组,需要使用应用权限(具体为Sites.Selected权限),同时应用仍需支持代表用户执行操作。
为尽可能收窄应用权限范围以保障API安全性,希望能够同时使用委托权限与应用权限。

已尝试操作

此前查阅的资料显示需要创建两个独立的Graph Client实例分别获取对应令牌,相关内容发布于2018年,当前技术栈已有较多更新。根据公开的Microsoft Identity Web官方文档说明,可使用同一个Graph实例,通过.WithAppOnly()和.WithScopes()方法指定调用时使用的权限类型。
当前使用Microsoft.Identity.Web库,通过.AddMicrosoftGraph方法注入服务,同时配置.WithAppOnly和.WithScopes,但应用权限始终无法生效:.WithScopes相关调用正常,但调用.WithAppOnly时抛出如下错误:

System.Collections.Generic.KeyNotFoundException: The given key 'Microsoft.Graph.AuthenticationHandlerOption' was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Microsoft.Identity.Web.BaseRequestExtensions.SetParameter[T](T baseRequest, Action`1 action)

Azure应用权限配置

Azure应用权限配置截图

SharePoint权限检查结果

{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('SITE_ID')/permissions/$entity",
"id": "PERMISSION ID",
"roles": [
    "write"
],
"grantedToIdentities": [
    {
        "application": {
            "displayName": "MY API",
            "id": "API CLIENT ID"
        }
    }
]
}

相关代码

Startup.cs

services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd")
        .EnableTokenAcquisitionToCallDownstreamApi()
        .AddMicrosoftGraph(Configuration.GetSection("Graph"))
        //.AddMicrosoftGraphAppOnly(authenticationProvider => new GraphServiceClient(authenticationProvider))
        .AddInMemoryTokenCaches();

appsettings.json

"AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "{ClientId}",
    "TenantId": "{TenantId}",
    "CallbackPath": "/signin-oidc",
    "Audience": "{ClientId}",

    "ClientSecret": "{ClientSecret}",
    "ClientCertificates": [
    ]
  },

  "Graph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "user.read",
    "DefaultScope": "https://graph.microsoft.com/.default"
  }

未添加.WithAppOnly的Graph调用可正常执行,但此时采用用户身份验证Graph Client,若用户无对应OneDrive组访问权限,调用会失败:

WorkbookSessionInfo res = await _graphServiceClient.Groups[_groupId].Drive.Items[productStructureCalculator.CalculatorId].Workbook
    .CreateSession(persistChanges)
    .Request()
    .WithAppOnly()
    .Header("Prefer", "respond-async")
    .PostAsync();

解决方案

报错原因

默认通过AddMicrosoftGraph注入的GraphServiceClient仅配置了委托权限场景的认证处理选项,缺少应用权限调用所需的AuthenticationHandlerOption配置,调用.WithAppOnly()时找不到对应配置项就会抛出字典找不到Key的异常。
另外微软官方文档提到的单实例切换权限类型的方案,要求Microsoft.Identity.Web和Microsoft.Graph的Nuget包版本匹配,低版本不支持该特性。

推荐方案:双实例注册(稳定性最高)

无需纠结单实例切换权限的兼容问题,分别注册委托权限、应用权限两个独立的GraphServiceClient实例即可,步骤如下:

  1. 修改Startup.cs注册逻辑:
// 注册代表用户调用的委托权限GraphClient(默认注入)
services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd")
        .EnableTokenAcquisitionToCallDownstreamApi()
        .AddMicrosoftGraph(Configuration.GetSection("Graph"))
        .AddInMemoryTokenCaches();

// 注册应用权限专用的GraphClient,使用键控服务避免冲突
services.AddKeyedSingleton<GraphServiceClient>("AppOnlyGraph", (sp, _) =>
{
    var tokenAcquisition = sp.GetRequiredService<ITokenAcquisition>();
    var authProvider = new BaseBearerTokenAuthenticationProvider(async (request) =>
    {
        var token = await tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default");
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    });
    return new GraphServiceClient(authProvider);
});
  1. 业务代码中按需注入对应实例使用:
// 构造函数注入两个实例
public YourService(GraphServiceClient userGraphClient, [FromKeyedServices("AppOnlyGraph")] GraphServiceClient appOnlyGraphClient)
{
    _userGraphClient = userGraphClient; // 委托权限,代表用户调用
    _appOnlyGraphClient = appOnlyGraphClient; // 应用权限,无需用户权限
}

// 应用权限调用无需加.WithAppOnly()
WorkbookSessionInfo res = await _appOnlyGraphClient.Groups[_groupId].Drive.Items[productStructureCalculator.CalculatorId].Workbook
    .CreateSession(persistChanges)
    .Request()
    .Header("Prefer", "respond-async")
    .PostAsync();

可选方案:单实例切换权限

如果坚持使用单实例,将Microsoft.Identity.Web和Microsoft.Graph Nuget包升级到最新稳定版,修改AddMicrosoftGraph配置即可:

services.AddMicrosoftGraph(options =>
{
    options.Scopes = "user.read";
    options.DefaultScope = "https://graph.microsoft.com/.default";
},
pipeline =>
{
    // 明确添加认证处理选项
    pipeline.AddAuthenticationHandler();
});

升级后即可正常使用.WithAppOnly()、.WithScopes()切换权限类型。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:57:02