SharePointOnline CSOM 401 Несанкционированное использование предоставленного токена доступа

Я создаю функцию, которая автоматизирует извлечение документов и других файлов 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;

Я пробовал несколько разных способов обойти это безрезультатно:

  • Я зашел в центр администрирования своего сайта SharePoint и предоставил приложению разрешения FullControl, а также дал приложению эти разрешения в Azure AD. Кажется, это ничего не изменило, я все еще получаю тот же 401.
  • Я зарегистрировал совершенно новое приложение непосредственно из центра администрирования дочернего сайта SharePoint и предоставил ему разрешения FullControl. Я использовал новый идентификатор клиента и секрет клиента, которые были сгенерированы, и смог вернуть токен доступа. Не повезло, все равно звоните 401 ClientContext.ExecuteQueryAsync()
  • Я попытался изменить свой siteUrl на URL-адрес конкретного сайта SharePoint (например, https://myorg.sharepoint.com/sites/mySite), но как только я это сделаю, я больше не могу получить токен доступа. Вместо этого я получаю исключение Msal, AADSTS500011, которое гласит:

«Субъект ресурса с именем https://myorg.sharepoint.com/sites/mysite не найден в тенанте с именем (мой тенант). Это может произойти, если приложение не было установлено администратором тенанта или с согласия любого пользователя в арендаторе. Возможно, вы отправили запрос проверки подлинности не тому арендатору.

  • Я также пытался использовать базу siteUrl для получения токена, а затем указывал URL-адрес сайта для ClientContext. Я получаю тот же результат 401.
  • Я пробовал несколько разных органов на случай, если предоставленный мне токен недействителен. Я пытался использовать URL-адрес токена V1, URL-адрес токена V2, без URL-адреса, специфичного для токена (только адрес центра по умолчанию + идентификатор клиента). Все они возвращают токен доступа, но ни один из них не избегает ошибки 401.
  • В статье документации MS предлагается добавить дополнительный «/» к запрошенной области .default в случаях, когда возвращается ошибка 401 (например, https://myorg.sharepoint.com/sites/mysite//.default). Кажется, это ничего не изменило.

У моего приложения, кажется, есть разрешения, необходимые для выполнения этой базовой операции чтения, но я постоянно получаю отказ. Я использую ClientID, ClientSecret и Tenant ID, скопированные непосредственно со страницы приложения AAD. Код, который я использую выше, рекомендован Microsoft для использования нового пакета SharePointOnline.CSOM. Что мне здесь не хватает?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Конструктор 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}";

Это не сработало для меня до сих пор. Сайт SharePoint, к которому я пытаюсь получить доступ, имеет полный URL-адрес (например, myorg.sharepoint.com/sites/mysite), но когда я использую этот URL-адрес, я больше не могу получить маркер доступа, и вместо этого я сказали, что ресурса не существует. Я могу перейти по тому же URL-адресу в своем браузере и открыть свою страницу. Если я попытаюсь использовать полный URL-адрес только для ClientContext, я все равно получу 401.

draconastar 10.02.2023 13:39
Ответ принят как подходящий

Я решил «решить» эту проблему, используя пакет 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 — самый чистый и надежный из всех, что я когда-либо встречал.

Другие вопросы по теме

Получение данных XLSX из Microsoft Sharepoint в запросе React/NodeJS
Как прочитать файл excel, присутствующий в онлайн-документе SharePoint на C#, затем мне нужно зашифровать некоторые столбцы и, наконец, записать его в базу данных Snowflake?
Как создать оператор if в списке точек доступа, который проверяет, есть ли в столбце «имя» знак «!» и на основе этого изменяет текущий столбец
Список SharePoint Добавить новую кнопку не открывает «форму нового элемента»
Sharepoint Online каждая веб-часть SPFx получает эту ошибку: Что-то пошло не так -> Несоответствующий анонимный модуль define ()
Получение ролей AAD из веб-части React SPFx
Powershell PnPListItem превышает ограничения
Как создать новую корневую папку в онлайн-библиотеке документов SharePoint с помощью Graph API в Python
Как создать числовое поле с префиксом (например, 00001), которое увеличивается при каждом добавлении документа в SharePoint Online?
Проблема с запросом OData в Microsoft Flow для действия GetItems в списке SharePoint, содержащем более 20000 строк