GraphAPI — запрос имен пользователей, имеющих определенную роль приложения

Я пытаюсь использовать GraphAPI v5 в приложении Blazor .NET 8.0, чтобы запросить список всех пользователей, которым назначена определенная роль приложения.

Я настраиваю роли в Entra Admin Center > Корпоративные приложения > (мое приложение) > Пользователи и группы и назначаю пользователям роли, которые я определил при регистрации приложения.

Я попробовал следующий код на странице Razor:

@inject GraphServiceClient GSC
@inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler

// ...

protected async Task AzTest()
{
    try
    {
        var users = await GSC.Users.GetAsync((requestConfiguration) =>
        {
        requestConfiguration.QueryParameters.Expand = new string[] { "appRoleAssignments" };
        });
    }
    catch(Exception ex)
    {
         ConsentHandler.HandleException(ex);
    }
}

Я также обнаружил (благодаря комментатору), что Directory.Read.All является необходимой областью действия для работы этого вызова.

Мой вопрос: как мне отфильтровать результат, чтобы найти только пользователей с определенной ролью? В моей организации более 1000 пользователей.

Я пробовал следующие подходы:

Подход 1 — Фильтр

Guid roleIdGuid = new Guid("5f61fba7-ae07-4438-9f41-4c00b2540463");
// ...
requestConfiguration.QueryParameters.Filter = $"appRoleAssignments/any(ar: ar/appRoleId eq {roleIdGuid})";

(это было предложено вторым пилотом). Это дает ошибку времени выполнения:

Microsoft.Graph.Models.ODataErrors.ODataError: Property 'appRoleId' does not exist as a declared property or extension property.

что, по мнению Copilot, означает, что API фактически не поддерживает фильтрацию по идентификатору роли приложения.

Подход 2 — Пагинация

Другой подход — получить всех пользователей через разбиение на страницы, а затем просмотреть их на C# для проверки идентификатора роли. Однако нумерация страниц, похоже, не работает. Используя точный код из документации V5:

var usersResponse = await graphServiceClient
     .Users
    .GetAsync(requestConfiguration => { 
    requestConfiguration.QueryParameters.Expand = new string[] { "appRoleAssignments" };
    requestConfiguration.QueryParameters.Top = 1; 
    });

var userList = new List<User>();
var pageIterator = PageIterator<User,UserCollectionResponse>.CreatePageIterator(graphServiceClient,usersResponse, (user) => { userList.Add(user); return true; });

await pageIterator.IterateAsync();
// (omitted the later filtering code for brevity)

Это запустилось, но я ждал более 90 секунд, а он все еще выполнял вызовы API и ответы со стороны await; Я не уверен, застрял ли он каким-то образом в бесконечном цикле или просто длился вечно, но в любом случае такая задержка не является приемлемым решением.

Привет, я просто хочу дважды подтвердить, выдаст ли var users = await GSC.Users.Request().GetAsync(); ошибку или нет. Насколько я понимаю, если мы хотим перечислить всех пользователей в клиенте, которые соответствуют какому-либо правилу, необходимо, по крайней мере, иметь разрешение на чтение каталога, например Directory.Read.All. Если у вас нет этого разрешения, боюсь, реализовать ваше требование невозможно.

Tiny Wang 18.07.2024 11:10

@TinyWang ок, добавление Directory.Read.All к запрошенным областям делает GSC.Users.Request().GetAsync() успешным, теперь я думаю, мой вопрос переходит к тому, какой правильный фильтр и т. д., чтобы получить информацию, которую я ищу

M.M 19.07.2024 07:23

Спасибо за Ваше подтверждение! А если не получится, возможно, нам еще понадобится User.Read.All.

Tiny Wang 19.07.2024 07:27

@TinyWang Я обновил вопрос сейчас, чтобы сосредоточиться на исходном вопросе, преодолев проблему с разрешениями.

M.M 24.07.2024 02:36

Привет! Судя по документу API, appRoleId не поддерживает фильтр. Фильтр поддержки свойств будет иметь соответствующее описание. Но результат вашего теста уже доказал, что это свойство не поддерживается.

Tiny Wang 24.07.2024 03:55

Тогда у меня уже был образец, и вы можете использовать его напрямую: stackoverflow.com/a/78079972/14574199

Tiny Wang 24.07.2024 03:58

Затем о requestConfiguration.QueryParameters.Top = 1; --> Я тестирую Top1, так как в моем тестовом клиенте всего 2 пользователя.... Вы можете использовать Top 999... аналогично этому случаю stackoverflow.com/a/78720008/14574199

Tiny Wang 24.07.2024 04:00
Для развертывания Сайтов с использованием Blazor, Angular и React с репозиторием на GitHub на Cloudflare
Для развертывания Сайтов с использованием Blazor, Angular и React с репозиторием на GitHub на Cloudflare
Как развернуть сайты с помощью Blazor, Angular и React с репозиторием на GitHub на Cloudflare.
0
7
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

appRoleId не поддерживает фильтр из документа API. Как видите, principalDisplayName поддерживает фильтр. Итак, я согласен с вами, что нам нужно получить всех пользователей, а затем самим назначить им определенные роли.

Что касается пагинации Graph API, мы могли бы установить размер страницы равным 999, чтобы минимизировать количество запросов, и я боюсь, что топ-1 — это причина, по которой вы так долго ждали.

Тогда наши коды будут похожи на

var usersResponse = await graphServiceClient.Users.GetAsync(requestConfiguration => { 
    requestConfiguration.QueryParameters.Expand = new string[] { "appRoleAssignments" };
    requestConfiguration.QueryParameters.Top = 999; 
    });

var userList = new List<User>();
var pageIterator = PageIterator<User,UserCollectionResponse>.CreatePageIterator(graphServiceClient,usersResponse, (user) => { userList.Add(user); return true; });

await pageIterator.IterateAsync();

List<User> result = new List<User>();
foreach (var tempUser in userList) {
    var roles = tempUser.AppRoleAssignments;
    foreach(var role in roles) {
        if (role.AppRoleId.ToString() == "role_id_here")
        {
            result.Add(tempUser);
            break;
        }
    }
}

Я заметил, что при запросе «топ-999» он возвращает только топ-100?

M.M 25.07.2024 05:13

спасибо за ваш ответ, разные API могут по-разному вести себя для максимального количества Максимина. Основываясь на вашем описании, я искал API и нашел In server-side paging, the Microsoft Graph service returns a default number of results in a single page without the client specifying the number of results to return using $top. For example, the GET /users endpoint returns a default of 100 results in a single page. по этой ссылке. Боюсь, API пользователя списка изменил максимальное верхнее значение. Я вспомнил, что это

Tiny Wang 25.07.2024 05:38

раньше было 999. А может я просто ошибся в памяти. В любом случае, не могли бы вы сообщить мне, сработало ли это для вас или нет? Сталкивались ли вы с проблемой столь долгого ожидания?

Tiny Wang 25.07.2024 05:38

На самом деле в арендаторе больше пользователей, чем я думал (более 20 000), поэтому даже страницы в 999 — это слишком медленно; Можете ли вы придумать какой-нибудь фильтр, который я мог бы использовать, чтобы немного сузить список? Фильтр endsWith(mail, 'mydomain.com') работает сам по себе, но API, похоже, не поддерживает его использование одновременно с параметром Expand.

M.M 25.07.2024 05:40

Боюсь, вам придется попробовать другие фильтры, я тестирую на своей стороне запрос https://graph.microsoft.com/v1.0/users?$expand=appRoleAssign‌​ments&$filter=userPr‌​incipalName eq '[email protected]', который работает хорошо, но если я использовал $expand=appRoleAssignments&$filter=endswith(userPrincipalNam‌​e,'[email protected]‌​oft.com'), это дало мне неподдерживаемую ошибку запроса, даже если это свойство поддерживает фильтрацию с помощью endswith. Это странно.

Tiny Wang 25.07.2024 08:30

Боюсь, у нас может быть обходной путь для создания группы, добавляющей в нее всех пользователей, имеющих определенную роль приложения. Я нашел этот случай, в котором использовался скрипт PowerShell. Мы также могли бы создать сценарий PowerShell, чтобы найти всех пользователей и добавить пользователей в эту группу.

Tiny Wang 25.07.2024 08:34

если я правильно понимаю, сценарий powershell применяет фильтр, а затем один за другим выполняет дальнейшие вызовы, чтобы проверить appRoleAssignment для каждого пользователя. Не идеально

M.M 26.07.2024 00:46

Привет, прошу прощения, что не четко выразил свою мысль. Я имею в виду, что мы можем попробовать PowerShell выполнить такую ​​задачу, как фоновая служба, которая поможет нам найти всех пользователей, а затем добавить их в группу, чтобы нас не заботила производительность. Ссылка, которой я поделился, хм, я просто хочу, чтобы вы увидели пример PowerShell для вызова API MS Graph, некоторые сценарии могут быть похожими, но это не одно и то же.

Tiny Wang 26.07.2024 03:56

ХОРОШО. чтобы уточнить, вы говорите, что вместо использования ролей для этой задачи при регистрации приложения мне лучше использовать группы?

M.M 28.07.2024 23:06

да, поскольку у нас нет хорошего API для выполнения этой задачи и получения всех пользователей с определенной ролью для обслуживания в будущем, возможно, другим вариантом может быть создание группы для этих пользователей. Кстати, мы могли бы даже дать роль группе. Доступен API для участников группы списков и группы listmemberOf.

Tiny Wang 29.07.2024 03:52

Этот ответ суммирует обсуждение комментариев

В настоящее время (июль 2024 г.) нет способа эффективно составить список всех пользователей с определенной ролью приложения; единственный способ — перечислить всех пользователей и проверить их роли на уровне приложения, что неприемлемо медленно, если, например, арендатор содержит более 20 000 пользователей.

Вместо этого систему можно было бы спроектировать для использования групп вместо ролей приложений. API поддерживает список членов группы.

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