Невозможно получить содержимое стенограммы через Graph API

Следуя документации Microsoft, нас пытаются вызвать Graph API для получения содержимого расшифровки.

Полезная информация:

MicrosoftAppType=MultiTenant
MicrosoftAppId=2dacff5b-9494-45b4-90f1-df6953d401aa

MicrosoftAppTenantId=91e213e9-498d-46b9-bc35-cd0aa9390b45

SubscriptionId=1106df7f-3a2b-4b98-80ff-7ab8738177d

MeetingID=MSpiYTc2OWFjOC0wOTc1LTRiOTctYTlmOS03NWFlYzZiNjEwMDQqMCoqMTk6bWVldGluZ19OV1ZsTmpoaU9Ua3RNV000WWkwME1HSmhMV0ZoT1RZdE0yUmlObVk0WmpnMk9HUTVAdGhyZWFkLnYy

TranscriptID=VjIjIzFiYTc2OWFjOC0wOTc1LTRiOTctYTlmOS03NWFlYzZiNjEwMDQ5MWUyMTNlOS00OThkLTQ2YjktYmMzNS1jZDBhYTkzOTBiNDUwNDAwMDAwMDgyMDBFMDAwNzRDNUI3MTAxQTgyRTAwODAwMDAwMDAwNDQ4MzI0ZjY2ZGQyZGEwMTAwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMGEzMWUzOWY1MDhhZWM5NGVhZWM2ZDlkYzEwMjIzNWQ3IyMwZjM1MWUxNy1mMjRjLTRiZmUtYTM4NC0zZDdmN2ZmODliMzE=

Разрешение приложения/RSC (мы добавили необходимое разрешение в манифест)

Сначала мы создали GraphClient с учетными данными нашего приложения следующим образом:

    // @azure/identityconst 
    credential = new ClientSecretCredential(
process.env.MicrosoftAppTenantId,
process.env.MicrosoftAppId,
process.env.MicrosoftAppPassword
);

    // @microsoft/microsoft-graph-client/authProviders/azureTokenCredentials
const authProvider = new TokenCredentialAuthenticationProvider(credential, { 
  ['https://graph.microsoft.com/.default']
});

    const graphClient = Client.initWithMiddleware({ authProvider: authProvider });

Мы успешно создали подписку следующим образом:

const transcriptSubscription = {
changeType: 'created',
notificationUrl: 'https://6ebd-2405-201-1021-7808-298c-d664-4dae-fff3.ngrok-free.app/notificationClient',
lifecycleNotificationUrl: 'https://6ebd-2405-201-1021-7808-298c-d664-4dae-fff3.ngrok-free.app/api/lifecycleNotifications',
resource: 'communications/onlineMeetings/getAllTranscripts?useResourceSpecificConsentBasedAuthorization=true',
includeResourceData: true,
encryptionCertificate: '{valid certificate}',
encryptionCertificateId:'{validId}',
expirationDateTime: '2024-07-11T11:00:00.0000000Z',
clientState: '{secretClientState}'
};

await graphClient.api('/subscriptions')        
     .post(transcriptSubscription).then((res) => 
     {
console.info('Subscription:', res);
}).catch((err) => {
console.info('Error:', err);
});

Результаты этого кода создают действительную подписку

res: {
  '@odata.context': 'https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity',
  id: '1106df7f-3a2b-4b98-80ff-7ab8738177d9',
  resource: 'communications/onlineMeetings/getAllTranscripts?useResourceSpecificConsentBasedAuthorization=true',
  applicationId: '2dacff5b-9494-45b4-90f1-df6953d401aa',
  changeType: 'created',
  clientState: '{secretClientState}',
  notificationUrl: 'https://6ebd-2405-201-1021-7808-298c-d664-4dae-fff3.ngrok-free.app/notificationClient',
  notificationQueryOptions: null,
  lifecycleNotificationUrl: 'https://6ebd-2405-201-1021-7808-298c-d664-4dae-fff3.ngrok-free.app/api/lifecycleNotifications',
  expirationDateTime: '2024-07-11T11:00:00Z',
  creatorId: 'b3d2c52d-3d02-43bf-bd27-6408d62af8a1',
  includeResourceData: true,
  latestSupportedTlsVersion: 'v1_2', // Other data}

Мы слушаем арендатора, поэтому события принимаются так, как ожидалось:

subscriptionId: '1106df7f-3a2b-4b98-80ff-7ab8738177d9',
changeType: 'created',
clientState: '{secretClientState}',
subscriptionExpirationDateTime: '2024-07-11T11:00:00+00:00',
resource: "communications/onlineMeetings('MSpiYTc2OWFjOC0wOTc1LTRiOTctYTlmOS03NWFlYzZiNjEwMDQqMCoqMTk6bWVldGluZ19OV1ZsTmpoaU9Ua3RNV000WWkwME1HSmhMV0ZoT1RZdE0yUmlObVk0WmpnMk9HUTVAdGhyZWFkLnYy')/transcripts('VjIjIzFiYTc2OWFjOC0wOTc1LTRiOTctYTlmOS03NWFlYzZiNjEwMDQ5MWUyMTNlOS00OThkLTQ2YjktYmMzNS1jZDBhYTkzOTBiNDUwNDAwMDAwMDgyMDBFMDAwNzRDNUI3MTAxQTgyRTAwODAwMDAwMDAwNDQ4MzI0ZjY2ZGQyZGEwMTAwMDAwMDAwMDAwMDAwMDAxMDAwMDAwMGEzMWUzOWY1MDhhZWM5NGVhZWM2ZDlkYzEwMjIzNWQ3IyMwZjM1MWUxNy1mMjRjLTRiZmUtYTM4NC0zZDdmN2ZmODliMzE=')",// Other data

Когда мы пытаемся вызвать API контента:

await graphClient
.api(`users/${ process.env.MicrosoftAppId }/onlineMeetings/${ meetingId }/transcripts/${ transcriptId }`)
.get()
.then((dataFromResponse) => {
console.info('### dataFromResponse:', dataFromResponse);
})
.catch((error) => {
console.info('### error:', error);
});

Мы получаем ответ об ошибке следующего содержания:

body: `{
"code":"Forbidden","message":"Application is not allowed to perform operations on the user '2dacff5b-9494-45b4-90f1-df6953d401aa', neither is allowed access through RSC permission evaluation.",
"innerError":{"date":"2024-07-10T02:45:09","request-id":"81fbbe48-d368-41d0-b5ab-f1a3e59f237a",
"client-request-id":"34e6cbfd-a622-0969-e57e-cc9c3c4e04c0"
}}`

Мое приложение участвует в подписке, и мы также пробовали использовать «бета-версию», но результат тот же.

Как получить расшифровку через Graph API?

🤔 А знаете ли вы, что...
С Node.js можно легко интегрировать с базами данных, такими как MongoDB и MySQL.


114
1

Ответ:

Решено

Первым делом:

Обязательно добавьте следующие разрешения API Microsoft Graph при регистрации приложения.

ОнлайнВстречи.Читать.Все
OnlineMeetingTranscript.Читать.Все

Дайте согласие администратора на разрешения API.

Второе:

Вам необходимо создать политику доступа к приложению, чтобы разрешить приложению доступ к онлайн-собраниям от имени пользователя.

Вот команды для настройки политики доступа к приложениям:

--> Импорт-модуль MicrosoftTeams
--> Connect-MicrosoftTeams
--> New-CsApplicationAccessPolicy -Identity «PolicyName» -AppIds «App-regID» -Description «Некоторое описание»
--> Grant-CsApplicationAccessPolicy -PolicyName «PolicyName» -Identity «UserID»

Предоставьте эту политику, используя свой идентификатор пользователя Azure.

После создания и предоставления этой политики доступа вы сможете использовать API Graph для доступа к содержимому стенограмм с использованием токена аутентификации регистрации вашего приложения.

Для справки: https://learn.microsoft.com/en-us/graph/cloud-communication-online-meeting-application-access-policy

Примечание. Не присваивайте политике статус -Global. Потому что тогда любой член арендатора сможет получить доступ к расшифровкам любых собраний.