问题陈述
我正在编写一个需要访问用户不一定有权访问的 OneDrive 组的应用程序。这(对我而言)意味着我需要使用应用程序权限,特别是“Sites.Selected”。然而,应用程序应该仍然能够代表用户做事。
我试图将应用程序权限保持在尽可能低的水平,以使 API 更加安全,因此如果我可以同时使用委托权限和应用程序权限,那就太好了。
我做了什么
根据我在这里阅读的内容,似乎我需要两个单独的 Graph Client 实例并为每个实例获取一个令牌。不过,这些帖子来自 2018 年,从那时起情况发生了很大变化。据此,似乎有可能拥有一个图形实例并使用 .WithAppOnly() 和 .WithScopes() 您可以告诉 Graph 女巫使用权限。
我目前正在将 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 应用权限
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"
}
}
]
}
代码
启动.cs
services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(Configuration.GetSection("Graph"))
//.AddMicrosoftGraphAppOnly(authenticationProvider => new GraphServiceClient(authenticationProvider))
.AddInMemoryTokenCaches();
应用设置.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"
}
Graph Call 在没有 .WithAppOnly 的情况下工作正常,但它仍在使用用户对 Graph 客户端进行身份验证(如果用户无权访问驱动器,则调用失败)
WorkbookSessionInfo res = await _graphServiceClient.Groups[_groupId].Drive.Items[productStructureCalculator.CalculatorId].Workbook
.CreateSession(persistChanges)
.Request()
.WithAppOnly()
.Header("Prefer", "respond-async")
.PostAsync();