Я создаю функцию, которая автоматизирует извлечение документов и других файлов SharePoint из веб-API, но мне трудно получить разрешение на выполнение даже базовых операций чтения. Я тестирую это в консольном приложении .NET 6, используя пакет Microsoft.SharePointOnline.CSOM NuGet.
Я зарегистрировал приложение в Azure Active Directory и предоставил ему разрешение Sites.Read.All. Я взял ClientID, ClientSecret и TenantID, сообщаемые этим зарегистрированным приложением, и я использую их в своем консольном приложении. Я могу получить токен доступа без проблем, и расшифровка JWT показывает, что он поставляется с разрешением Sites.Read.All. Но независимо от того, что я пытаюсь сделать, ClientContext.ExecuteQueryAsync()
постоянно выдает исключение, жалуясь на то, что удаленный сервер ответил ошибкой 401.
Вот код, который я тестирую:
var clientId = "myClientId";
var clientSecret = "myClientSecret";
var tenantId = "myTenantId";
var authority = "https://login.microsoftonline.com/" + tenantId;
var siteUrl = "https://myorg.sharepoint.com";
var app = new ConfidentialClientApplicationBuilder
.Create()
.WithClientSecret(clientSecret)
.WithAuthority(authority)
.WithTenantId(tenantId)
.Build();
var paramBuilder = app.AcquireTokenForClient(new[] { siteUrl + "/.default" });
var authResult = await paramBuilder.ExecuteAsync();
// authResult has successfully retrieved an access token at this point
var context = new ClientContext(siteUrl);
context.ExecutingWebRequest += (_, e) =>
{
e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + authResult.AccessToken;
}
context.Load(context.Web);
await context.ExecuteQueryAsync(); // 401 is thrown here
var title = context.Web.Title;
Я пробовал несколько разных способов обойти это безрезультатно:
ClientContext.ExecuteQueryAsync()
siteUrl
на URL-адрес конкретного сайта SharePoint (например, https://myorg.sharepoint.com/sites/mySite), но как только я это сделаю, я больше не могу получить токен доступа. Вместо этого я получаю исключение Msal, AADSTS500011, которое гласит:«Субъект ресурса с именем https://myorg.sharepoint.com/sites/mysite не найден в тенанте с именем (мой тенант). Это может произойти, если приложение не было установлено администратором тенанта или с согласия любого пользователя в арендаторе. Возможно, вы отправили запрос проверки подлинности не тому арендатору.
siteUrl
для получения токена, а затем указывал URL-адрес сайта для ClientContext
. Я получаю тот же результат 401.У моего приложения, кажется, есть разрешения, необходимые для выполнения этой базовой операции чтения, но я постоянно получаю отказ. Я использую ClientID, ClientSecret и Tenant ID, скопированные непосредственно со страницы приложения AAD. Код, который я использую выше, рекомендован Microsoft для использования нового пакета SharePointOnline.CSOM. Что мне здесь не хватает?
Конструктор ClientContext
требует URL сайта, включая название сайта.
var clientId = "myClientId";
var clientSecret = "myClientSecret";
var tenantId = "myTenantId";
var authority = "https://login.microsoftonline.com/" + tenantId;
var siteUrl = "https://myorg.sharepoint.com";
var siteName = "MySiteName";
var app = new ConfidentialClientApplicationBuilder
.Create()
.WithClientSecret(clientSecret)
.WithAuthority(authority)
.WithTenantId(tenantId)
.Build();
var paramBuilder = app.AcquireTokenForClient(new[] { siteUrl + "/.default" });
var authResult = await paramBuilder.ExecuteAsync();
// authResult has successfully retrieved an access token at this point
var webFullUrl = $"{siteUrl}/sites/{siteName}";
var context = new ClientContext(webFullUrl);
Если сайт имеет префикс
var webFullUrl = $"{siteUrl}/sites/{sitePrefix}/{siteName}";
Я решил «решить» эту проблему, используя пакет NuGet PnP.Framework вместо Microsoft.SharePointOnline.CSOM. Я больше ничего не изменил в регистрации моего приложения или назначенных ему разрешениях, и PnP.Framework смог справиться с этим без проблем (и с меньшим количеством аргументов). Кажется, он знает что-то, чего не знает SharePointOnline.CSOM, учитывая, что работает следующее простое консольное приложение:
using System;
using PnP.Framework
const string clientId = "myClientId";
const string clientSecret = "myClientSecret";
const string siteUrl = "https://myorg.sharepoint.com/sites/mysite";
using var clientContext = new AuthenticationManager()
.GetACSAppOnlyContext(siteUrl, clientId, clientSecret);
cc.Load(cc.Web);
await cc.ExecuteQueryAsync(); // no longer throws a 401
Console.WriteLine(cc.Web.Title); // prints my site's title
Я попытался использовать более новый пакет SDK PnP.Core, но не смог найти никакой документации или примеров того, как заставить этот пакет работать с контекстом аутентификации клиента только для приложения. API PnP.Framework — самый чистый и надежный из всех, что я когда-либо встречал.
Это не сработало для меня до сих пор. Сайт SharePoint, к которому я пытаюсь получить доступ, имеет полный URL-адрес (например, myorg.sharepoint.com/sites/mysite), но когда я использую этот URL-адрес, я больше не могу получить маркер доступа, и вместо этого я сказали, что ресурса не существует. Я могу перейти по тому же URL-адресу в своем браузере и открыть свою страницу. Если я попытаюсь использовать полный URL-адрес только для
ClientContext
, я все равно получу 401.