Создание надстройки Office на платформе Node.js с использованием единого входа

Пользователи могут входить в Office, а веб-надстройка Office может воспользоваться этим процессом входа, чтобы авторизовать пользователей в надстройке и Microsoft Graph, не требуя от пользователей повторного входа. Общие сведения см. в статье Включение единого входа в надстройке Office.

В этой статье описывается процесс включения единого входа (SSO) в надстройке. Создаваемый образец надстройки состоит из двух частей. область задач, загружаемая в Microsoft Excel, и сервер среднего уровня, обрабатывающий вызовы Microsoft Graph для области задач. Сервер среднего уровня создается с помощью Node.js и Express и предоставляет один REST API , /getuserfilenamesкоторый возвращает список первых 10 имен файлов в папке OneDrive пользователя. Область задач использует getAccessToken() метод для получения маркера доступа для пользователя, выполнившего вход на сервер среднего уровня. Сервер среднего уровня использует поток On-Behalf-Of (OBO) для обмена маркером доступа на новый с доступом к Microsoft Graph. Этот шаблон можно расширить для доступа к любым данным Microsoft Graph. Область задач всегда вызывает REST API среднего уровня (передавая маркер доступа), когда ей требуются службы Microsoft Graph. Средний уровень использует маркер, полученный через OBO, для вызова служб Microsoft Graph и возврата результатов в область задач.

Эта статья работает с надстройкой, которая использует Node.js и Express. Аналогичная статья, посвященная надстройке на основе ASP.NET, — Создание надстройки Office на платформе ASP.NET с использованием единого входа.

Необходимые компоненты

  • Node.js (последняя версия LTS)

  • Git Bash (или другой клиент git).

  • Редактор кода— мы рекомендуем Visual Studio Code

  • По крайней мере несколько файлов и папок, хранящихся в OneDrive для бизнеса в подписке Microsoft 365

  • Сборка Microsoft 365, поддерживающая набор требований IdentityAPI 1.3. Вы можете получить подписку на Microsoft 365 E5 разработчика, которая включает в себя песочницу для разработчиков, в рамках программы разработчика Microsoft 365. Дополнительные сведения см. в разделе Вопросы и ответы. Песочница разработчика включает подписку Microsoft Azure, которую можно использовать для регистрации приложений на последующих шагах в этой статье. При желании для регистрации приложений можно использовать отдельную подписку Microsoft Azure. Получите пробную подписку на Microsoft Azure.

Настройка начального проекта

  1. Клонируйте или скачайте репозиторий Office-Add-in-NodeJS-SSO.

    Примечание.

    Существует две версии примера.

    • Папка Begin является начальным проектом. Пользовательский интерфейс и другие аспекты надстройки, не связанные непосредственно с единым входом и авторизацией, уже готовы. В последующих разделах этой статьи рассматривается доработка проекта.
    • Папка Complete содержит один и тот же пример со всеми инструкциями по написанию кода из этой статьи. Чтобы использовать завершенную версию, просто следуйте инструкциям в этой статье, но замените "Begin" на "Complete" (Завершить) и пропустите разделы Код на стороне клиента и Код на стороне сервера среднего уровня .
  2. Откройте командную строку в папке Begin .

  3. Введите в консоли команду npm install, чтобы установить все зависимости, указанные в файле package.json.

  4. Выполните команду npm run install-dev-certs. При запросе нажмите Да, чтобы установить сертификат.

Используйте следующие значения заполнителей для последующих шагов регистрации приложения.

Заполнитель Значение
<add-in-name> Office-Add-in-NodeJS-SSO
<fully-qualified-domain-name> localhost:3000
Разрешения Microsoft Graph profile, openid, Files.Read

Регистрация надстройки с помощью платформа удостоверений Майкрософт

Необходимо создать регистрацию приложения в Azure, представляющего веб-сервер. Это обеспечивает поддержку проверки подлинности, чтобы в коде клиента в JavaScript можно было выдавать правильные маркеры доступа. Эта регистрация поддерживает как единый вход в клиенте, так и резервную проверку подлинности с помощью библиотеки проверки подлинности Майкрософт (MSAL).

  1. Войдите в портал Azure с учетными данными администратора в клиенте Microsoft 365. Например, MyName@contoso.onmicrosoft.com.

  2. Выберите Регистрация приложений. Если значок не отображается, найдите "регистрация приложения" в строке поиска.

    Домашняя страница портал Azure.

    Появится страница регистрации приложений.

  3. Выберите Новая регистрация.

    Новая регистрация на панели Регистрация приложений.

    Появится страница Регистрация приложения.

  4. На страницеЗарегистрировать приложение задайте необходимые значения следующим образом.

    • Введите имя<add-in-name>.
    • Задайте для значения Поддерживаемые типы учетных записейзначение Учетные записи в любом каталоге организации (любой каталог Azure AD — мультитенантный) и личных учетных записей Майкрософт (например, Skype, Xbox).
    • Задайте URI перенаправления, чтобы использовать одностраничное приложение платформы (SPA), а URI — .https://<fully-qualified-domain-name>/dialog.html

    Зарегистрируйте область приложения с именем и поддерживаемой учетной записью.

  5. Нажмите Зарегистрировать. Появится сообщение о том, что регистрация приложения создана.

    Сообщение о том, что регистрация приложения создана.

  6. Скопируйте и сохраните значения идентификатора приложения (клиента) и идентификатора каталога (клиента). Они понадобятся вам позже.

    Область регистрации приложений для Contoso с идентификатором клиента и идентификатором каталога.

Добавление секрета клиента

Секрет клиента, который иногда называется паролем приложения, — это строковое значение, которое приложение может использовать вместо сертификата для идентификации себя.

  1. В области слева выберите Сертификаты & секреты. Затем на вкладке Секреты клиента выберите Новый секрет клиента.

    Область

    Откроется панель Добавление секрета клиента .

  2. Добавьте описание секрета клиента.

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

    • Время существования секрета клиента ограничено двумя годами (24 месяцами) или менее. Нельзя указать пользовательское время существования, превышающее 24 месяца.
    • Корпорация Майкрософт рекомендует установить срок действия менее 12 месяцев.

    Добавьте область секретов клиента с описанием и истекает срок действия.

  4. Нажмите Добавить. Создается новый секрет, а значение временно отображается.

Важно!

Запишите значение секрета для использования в коде клиентского приложения. Это значение секрета больше не отображается после выхода из этой области.

Предоставление веб-API

  1. В области слева выберите Предоставить API.

    Откроется панель Предоставление API .

    Область Предоставления API для регистрации приложения.

  2. Выберите Задать , чтобы создать универсальный код ресурса (URI) идентификатора приложения.

    Кнопка

    Раздел для задания URI идентификатора приложения отображается с созданным URI идентификатора приложения в формате api://<app-id>.

  3. Обновите URI идентификатора приложения на api://<fully-qualified-domain-name>/<app-id>.

    Измените область URI идентификатора приложения, указав для порта localhost значение 44355.

    • URI идентификатора приложения предварительно заполняется идентификатором приложения (GUID) в форматеapi://<app-id>.
    • Формат URI идентификатора приложения должен иметь следующий формат: api://<fully-qualified-domain-name>/<app-id>
    • Вставьте между fully-qualified-domain-nameapi:// и <app-id> (который является GUID). Например, api://contoso.com/<app-id>.
    • Если вы используете localhost, формат должен иметь формат api://localhost:<port>/<app-id>. Например, api://localhost:3000/c6c1f32b-5e55-4997-881a-753cc1d563b7.

    Дополнительные сведения о URI идентификатора приложения см. в разделе Идентификатор манифеста приложения.

    Примечание.

    Если возникает ошибка с сообщением о том, что домен уже занят, но при этом вы являетесь его владельцем, следуйте процедуре в статье Краткое руководство. Добавление имени личного домена в Azure Active Directory, чтобы зарегистрировать его, а затем повторите этот шаг. (Эта ошибка также может возникнуть, если вы не выполнили вход с учетными данными администратора в клиенте Microsoft 365. См. шаг 2. Выйдите и снова войдите с учетными данными администратора и повторите процесс из шага 3.)

Добавление область

  1. На странице Предоставление API выберите Добавить область.

    Нажмите кнопку Добавить область.

    Откроется панель Добавление область.

  2. В области Добавление область укажите атрибуты область. В следующей таблице показаны примеры значений для надстройки и Outlook, для которых требуются profileразрешения , openid, Files.ReadWriteи Mail.Read . Измените текст в соответствии с разрешениями, которые требуются надстройке.

    Поле Описание Values
    Имя области Имя область. Общее соглашение об именовании область — .resource.operation.constraint Для единого входа необходимо задать значение access_as_user.
    Кто может согласиться Определяет, требуется ли согласие администратора или пользователи могут предоставить согласие без одобрения администратора. Для изучения единого входа и примеров рекомендуется задать для этого параметра значение Администраторы и пользователи.

    Выберите Администраторы только для более привилегированных разрешений.
    отображаемое имя согласия Администратор Краткое описание назначения область, видимое только администраторам. Read/write permissions to user files. Read permissions to user mail and profiles.
    описание согласия Администратор Более подробное описание разрешения, предоставленного область, которое видят только администраторы. Allow Office to have read/write permissions to all user files and read permissions to all user mail. Office can call the app's web APIs as the current user.
    Отображаемое имя согласия пользователя Краткое описание назначения область. Отображается для пользователей только в том случае, если для администраторов и пользователей задан параметр Кто может предоставить согласие. Read/write permissions to your files. Read permissions to your mail and profile.
    Описание согласия пользователя Более подробное описание разрешения, предоставляемого область. Отображается для пользователей только в том случае, если для администраторов и пользователей задан параметр Кто может предоставить согласие. Allow Office to have read/write permissions to your files, and read permissions to your mail and profile.
  3. Задайте для параметра Состояниезначение Включено, а затем выберите Добавить область.

    Задайте для параметра Состояние включено и нажмите кнопку Добавить область.

    Новый область, который вы определили, отображается на панели.

    Новая область отображается на панели Предоставление API.

    Примечание.

    Доменная часть имени области, отображаемая непосредственно под текстовым полем, должна автоматически соответствовать URI идентификатора приложения, заданного на предыдущем шаге, с добавлением /access_as_user в конце, например: api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user.

  4. Выберите Добавить клиентское приложение.

    Выберите Добавить клиентское приложение.

    Откроется панель Добавление клиентского приложения .

  5. В поле Идентификатор клиента введите ea5a67f6-b6f3-4338-b240-c655ddc3cc8e. Это значение предварительно разрешает все конечные точки приложений Microsoft Office. Если вы также хотите предварительно авторизовать Office при использовании в Microsoft Teams, добавьте 1fec8e78-bce4-4aaf-ab1b-5451cc387264 (Microsoft Teams desktop и Teams mobile) и 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 (Teams в Интернете).

    Примечание.

    Идентификатор ea5a67f6-b6f3-4338-b240-c655ddc3cc8e предварительно авторизует Office на всех следующих платформах. Кроме того, можно ввести соответствующее подмножество следующих идентификаторов, если по какой-либо причине вы хотите запретить авторизацию Office на некоторых платформах. В этом случае оставьте идентификаторы платформ, с которых вы хотите удержать авторизацию. Пользователи надстройки на этих платформах не смогут вызывать веб-API, но другие функции надстройки по-прежнему будут работать.

    • d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office).
    • 93d53678-613d-4013-afc1-62e9e444a0a5 (Office в Интернете).
    • bc59ab01-8403-45c6-8796-ac3ef710b3e3 (Outlook в Интернете).
  6. В разделе Авторизованные области установите api://<fully-qualified-domain-name>/<app-id>/access_as_user флажок.

  7. Нажмите кнопку Добавить приложение.

    Панель Добавление клиентского приложения.

Добавление разрешений Microsoft Graph

  1. В области слева выберите Разрешения API.

    Область разрешений API.

    Откроется область разрешений API .

  2. Выберите Добавить разрешение.

    Добавление разрешения на область разрешений API.

    Откроется область Запрашивать разрешения API .

  3. Выберите Microsoft Graph.

    Панель Запрашивать разрешения API с помощью кнопки Microsoft Graph.

  4. Выберите Делегированные разрешения.

    Панель Запрашивать разрешения API с делегированными разрешениями.

  5. В поле поиска Выбор разрешений найдите разрешения, необходимые надстройке. Например, для надстройки Outlook можно использовать profile, , openidFiles.ReadWriteи Mail.Read.

    Примечание.

    Разрешение User.Read может быть уже указано по умолчанию. Рекомендуется запрашивать только необходимые разрешения, поэтому рекомендуется снять флажок для этого разрешения, если надстройка не нуждается в нем.

  6. Установите флажки для каждого разрешения, как оно отображается. Обратите внимание, что разрешения не будут отображаться в списке при выборе каждого из них. Выбрав разрешения, необходимые надстройке, выберите Добавить разрешения.

    Область Запрашивать разрешения API с выбранными разрешениями.

  7. Выберите Предоставить согласие администратора для [имя клиента]. Выберите Да , чтобы появилось подтверждение.

Настройка версии маркера доступа

Необходимо определить версию маркера доступа, приемлемую для вашего приложения. Эта конфигурация выполняется в манифесте приложения Azure Active Directory.

Определение версии маркера доступа

Версия маркера доступа может измениться, если вы выбрали тип учетной записи, отличной от Учетные записи в любом каталоге организации (любой каталог Azure AD — мультитенантный), и личные учетные записи Майкрософт (например, Skype, Xbox). Выполните следующие действия, чтобы убедиться, что версия маркера доступа правильна для использования единого входа Office.

  1. В левой области выберите Манифест.

    Выберите Манифест Azure.

    Откроется манифест приложения Azure Active Directory.

  2. Введите 2 в качестве значения свойства accessTokenAcceptedVersion.

    Значение для принятой версии маркера доступа.

  3. Нажмите кнопку Сохранить.

    В браузере появится сообщение об успешном обновлении манифеста.

    Сообщение об обновлении манифеста.

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

Настройка надстройки

  1. Откройте папку \Begin в скопированном проекте в редакторе кода.

  2. .ENV Откройте файл и используйте значения, скопированные ранее из регистрации приложения Office-Add-in-NodeJS-SSO. Задайте значения следующим образом:

    Имя Значение
    CLIENT_ID Идентификатор приложения (клиента) на странице обзора регистрации приложения.
    CLIENT_SECRET Секрет клиента , сохраненный на странице "Сертификаты & секреты ".

    Значения не должны быть заключены в кавычки. По завершении файл должен выглядеть следующим образом.

    CLIENT_ID=8791c036-c035-45eb-8b0b-265f43cc4824
    CLIENT_SECRET=X7szTuPwKNts41:-/fa3p.p@l6zsyI/p
    NODE_ENV=development
    SERVER_SOURCE=<https://localhost:3000>
    
  3. Откройте файл манифеста надстройки manifest\manifest_local.xml и прокрутите его до конца. Сразу над конечным </VersionOverrides> тегом вы найдете следующую разметку.

    <WebApplicationInfo>
      <Id>$app-id-guid$</Id>
      <Resource>api://localhost:3000/$app-id-guid$</Resource>
      <Scopes>
          <Scope>Files.Read</Scope>
          <Scope>profile</Scope>
          <Scope>openid</Scope>
      </Scopes>
    </WebApplicationInfo>
    
  4. Замените заполнитель "$app-id-guid$" в обоих местах в разметке идентификатором приложения , скопированным при создании регистрации приложения Office-Add-in-NodeJS-SSO . Символы "$" не являются частью идентификатора, поэтому не включайте их. Это тот же идентификатор, который использовался для CLIENT_ID в . ENV-файл.

    Примечание.

    Значение <ресурса> — это универсальный код ресурса (URI) идентификатора приложения , заданный при регистрации надстройки. Раздел <Области> используется только для создания диалогового окна согласия, если надстройка продается через AppSource.

  5. Откройте файл \public\javascripts\fallback-msal\authConfig.js. Замените заполнитель "$app-id-guid$" идентификатором приложения, сохраненным из созданной ранее регистрации приложения Office-Add-in-NodeJS-SSO .

  6. Сохраните изменения в файле.

Код на стороне клиента

Вызов REST API веб-сервера

  1. Откройте файл public\javascripts\ssoAuthES6.js в редакторе кода. В нем уже есть код, гарантирующий поддержку обещаний, даже в элементе управления webview Trident (Интернет-Обозреватель 11), а Office.onReady также вызов, чтобы назначить обработчик единственной кнопке надстройки.

    Примечание.

    Как следует из названия, ssoAuthES6.js использует синтаксис JavaScript ES6, так как применение async и await хорошо демонстрирует простоту API единого входа. При запуске сервера localhost этот файл преобразуется в синтаксис ES5, чтобы пример поддерживал Trident.

  2. В функции getFileNameList замените TODO 1 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • Функция getFileNameList вызывается, когда пользователь нажимает кнопку Получить имена файлов OneDrive в области задач.
    • Он вызывает функцию, callWebServerAPI указывающую, какой REST API следует вызвать. При этом возвращается json, содержащий список имен файлов из OneDrive пользователя.
    • Json передается в функцию writeFileNamesToOfficeDocument для вывода имен файлов в документе.
    try {
        const jsonResponse = await callWebServerAPI('GET', '/getuserfilenames');
        if (jsonResponse === null) {
            // Null is returned when a message was displayed to the user
            // regarding an authentication error that cannot be resolved.
            return;
        }
        await writeFileNamesToOfficeDocument(jsonResponse);
        showMessage('Your OneDrive filenames are added to the document.');
    } catch (error) {
        console.log(error.message);
        showMessage(error.message);
    }
    
  3. В функции callWebServerAPI замените TODO 2 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • Функция вызывает getAccessToken функцию, которая является нашей собственной функцией, которая инкапсулирует с помощью единого входа Office или резервной копии MSAL по мере необходимости для получения маркера. Если возвращается маркер NULL, отображается сообщение об ошибке проверки подлинности, которое не может быть разрешено, поэтому функция также возвращает значение NULL.
    • Функция использует fetch API для вызова веб-сервера и в случае успешного выполнения возвращает текст JSON.
    const accessToken = await getAccessToken(authSSO);
    if (accessToken === null) {
        return null;
    }
    const response = await fetch(path, {
        method: method,
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + accessToken,
        },
    });
    
    // Check for success condition: HTTP status code 2xx.
    if (response.ok) {
        return response.json();
    }
    
  4. В функции callWebServerAPI замените TODO 3 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • Этот код обрабатывает сценарий, в котором истек срок действия маркера единого входа. В этом случае необходимо вызвать, Office.auth.getAccessToken чтобы получить обновленный маркер. Самый простой способ — выполнить рекурсивный вызов, который приводит к новому вызову Office.auth.getAccessToken. Параметр retryRequest гарантирует, что попытка рекурсивного вызова выполняется только один раз.
    • Строка TokenExpiredError устанавливается нашим веб-сервером при каждом обнаружении маркера с истекшим сроком действия.
     // Check for fail condition: Is SSO token expired? If so, retry the call which will get a refreshed token.
    const jsonBody = await response.json();
    if (
        authSSO === true &&
        jsonBody != null &&
        jsonBody.type === 'TokenExpiredError'
    ) {
        if (!retryRequest) {
            return callWebServerAPI(method, path, true); // Try the call again. The underlying call to Office JS getAccessToken will refresh the token.
        } else {
            // Indicates a second call to retry and refresh the token failed.
            authSSO = false;
            return callWebServerAPI(method, path, true); // Try the call again, but now using MSAL fallback auth.
        }
    }
    
  5. В функции callWebServerAPI замените TODO 4 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • Строка Microsoft Graph устанавливается нашим веб-сервером при сбое вызова Microsoft Graph.
    // Check for fail condition: Did we get a Microsoft Graph API error, which is returned as bad request (403)?
    if (response.status === 403 && jsonBody.type === 'Microsoft Graph') {
        throw new Error('Microsoft Graph error: ' + jsonBody.errorDetails);
    }
    
  6. В функции callWebServerAPI замените TODO 5 приведенным ниже кодом.

    // Handle other errors.
    throw new Error(
        'Unknown error from web server: ' + JSON.stringify(jsonBody)
    );
    
  7. В функции getAccessToken замените TODO 6 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • authSSO отслеживает, используется ли единый вход или используется резервный msal. Если используется единый вход, функция вызывает Office.auth.getAccessToken и возвращает маркер.
    • Ошибки обрабатываются функцией handleSSOErrors , которая возвращает маркер, если она переключится на резервную проверку подлинности MSAL.
    • Резервная проверка подлинности использует библиотеку MSAL для входа пользователя. Сама надстройка является SPA и использует регистрацию приложения SPA для доступа к веб-серверу.
    if (authSSO) {
        try {
            // Get the access token from Office host using SSO.
            // Note that Office.auth.getAccessToken modifies the options parameter. Create a copy of the object
            // to avoid modifying the original object.
            const options = JSON.parse(JSON.stringify(ssoOptions));
            const token = await Office.auth.getAccessToken(options);
            return token;
        } catch (error) {
            console.log(error.message);
            return handleSSOErrors(error);
        }
    } else {
        // Get access token through MSAL fallback.
        try {
            const accessToken = await getAccessTokenMSAL();
            return accessToken;
        } catch (error) {
            console.log(error);
            throw new Error(
                'Cannot get access token. Both SSO and fallback auth failed. ' +
                    error
            );
        }
    }
    
  8. В функции handleSSOErrors замените TODO 7 приведенным ниже кодом. Дополнительные сведения об этих ошибках см. в статье Устранение ошибок единого входа в надстройках Office.

    switch (error.code) {
        case 13001:
            // No one is signed into Office. If the add-in cannot be effectively used when no one
            // is logged into Office, then the first call of getAccessToken should pass the
            // `allowSignInPrompt: true` option. Since this sample does that, you should not see
            // this error.
            showMessage(
                'No one is signed into Office. But you can use many of the add-ins functions anyway. If you want to log in, press the Get OneDrive File Names button again.'
            );
            break;
        case 13002:
            // The user aborted the consent prompt. If the add-in cannot be effectively used when consent
            // has not been granted, then the first call of getAccessToken should pass the `allowConsentPrompt: true` option.
            showMessage(
                'You can use many of the add-ins functions even though you have not granted consent. If you want to grant consent, press the Get OneDrive File Names button again.'
            );
            break;
        case 13006:
            // Only seen in Office on the web.
            showMessage(
                'Office on the web is experiencing a problem. Please sign out of Office, close the browser, and then start again.'
            );
            break;
        case 13008:
            // Only seen in Office on the web.
            showMessage(
                'Office is still working on the last operation. When it completes, try this operation again.'
            );
            break;
        case 13010:
            // Only seen in Office on the web.
            showMessage(
                "Follow the instructions to change your browser's zone configuration."
            );
            break;
    
  9. Замените TODO 8 приведенным ниже кодом. Для любых ошибок, которые не могут быть обработаны, код переключается на резервную проверку подлинности с помощью MSAL.

    default: //recursive call.
            // For all other errors, including 13000, 13003, 13005, 13007, 13012, and 50001, fall back
            // to MSAL sign-in.
            showMessage('SSO failed. Trying fallback auth.');
            authSSO = false;
            return getAccessToken(false);
    }
    return null; // Return null for errors that show a message to the user.
    

Код REST API веб-сервера

Веб-сервер предоставляет REST API для вызова клиентом. Например, REST API /getuserfilenames получает список имен файлов из папки OneDrive пользователя. Каждому вызову REST API требуется маркер доступа клиента, чтобы убедиться, что правильный клиент обращается к своим данным. Маркер доступа обменивается на маркер Microsoft Graph через поток On-Behalf-Of (OBO). Новый токен Microsoft Graph кэшируется библиотекой MSAL для последующих вызовов API. Он никогда не отправляется за пределы веб-сервера. Дополнительные сведения см. в разделе Запрос маркера доступа среднего уровня.

Создание маршрута и реализация потока On-Behalf-Of

  1. Откройте файл routes\getFilesRoute.js и замените TODO 9 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • Он вызывает .authHelper.validateJwt Это гарантирует, что маркер доступа действителен и не был изменен.
    • Дополнительные сведения см. в разделе Проверка маркеров.
    router.get(
     "/getuserfilenames",
     authHelper.validateJwt,
     async function (req, res) {
       // TODO 10: Exchange the access token for a Microsoft Graph token
       //          by using the OBO flow.
     }
    );
    
  2. Замените TODO 10 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • Он запрашивает только необходимые минимальные области, например files.read.
    • Он использует MSAL authHelper для выполнения потока OBO в вызове acquireTokenOnBehalfOf.
    try {
      const authHeader = req.headers.authorization;
      let oboRequest = {
        oboAssertion: authHeader.split(' ')[1],
        scopes: ["files.read"],
      };
    
      // The Scope claim tells you what permissions the client application has in the service.
      // In this case we look for a scope value of access_as_user, or full access to the service as the user.
      const tokenScopes = jwt.decode(oboRequest.oboAssertion).scp.split(' ');
      const accessAsUserScope = tokenScopes.find(
        (scope) => scope === 'access_as_user'
      );
      if (!accessAsUserScope) {
        res.status(401).send({ type: "Missing access_as_user" });
        return;
      }
      const cca = authHelper.getConfidentialClientApplication();
      const response = await cca.acquireTokenOnBehalfOf(oboRequest);
      // TODO 11: Call Microsoft Graph to get list of filenames.
    } catch (err) {
      // TODO 12: Handle any errors.
    }
    
  3. Замените TODO 11 приведенным ниже кодом. Вот что нужно знать об этом коде:

    • Он создает URL-адрес для вызова Microsoft API Graph, а затем выполняет вызов через функцию getGraphData .
    • Он возвращает ошибки, отправляя ответ HTTP 500 вместе с подробными сведениями.
    • При успешном выполнении он возвращает клиенту json со списком имен файлов.
    // Minimize the data that must come from MS Graph by specifying only the property we need ("name")
    // and only the top 10 folder or file names.
    const rootUrl = '/me/drive/root/children';
    
    // Note that the last parameter, for queryParamsSegment, is hardcoded. If you reuse this code in
    // a production add-in and any part of queryParamsSegment comes from user input, be sure that it is
    // sanitized so that it cannot be used in a Response header injection attack.
    const params = '?$select=name&$top=10';
    
    const graphData = await getGraphData(
      response.accessToken,
      rootUrl,
      params
    );
    
    // If Microsoft Graph returns an error, such as invalid or expired token,
    // there will be a code property in the returned object set to a HTTP status (e.g. 401).
    // Return it to the client. On client side it will get handled in the fail callback of `makeWebServerApiCall`.
    if (graphData.code) {
      res
        .status(403)
        .send({
          type: "Microsoft Graph",
          errorDetails:
            "An error occurred while calling the Microsoft Graph API.\n" +
            graphData,
        });
    } else {
      // MS Graph data includes OData metadata and eTags that we don't need.
      // Send only what is actually needed to the client: the item names.
      const itemNames = [];
      const oneDriveItems = graphData["value"];
      for (let item of oneDriveItems) {
        itemNames.push(item["name"]);
      }
    
      res.status(200).send(itemNames);
    }
    // TODO 12: Check for expired token.
    
  4. Замените TODO 12 на приведенный ниже код. Этот код специально проверяет, истек ли срок действия маркера, так как клиент может запросить новый маркер и снова вызвать.

    } catch (err) {
       // On rare occasions the SSO access token is unexpired when Office validates it,
       // but expires by the time it is used in the OBO flow. Microsoft identity platform will respond
       // with "The provided value for the 'assertion' is not valid. The assertion has expired."
       // Construct an error message to return to the client so it can refresh the SSO token.
       if (err.errorMessage.indexOf('AADSTS500133') !== -1) {
         res.status(401).send({ type: "TokenExpiredError", errorDetails: err });
       } else {
         res.status(403).send({ type: "Unknown", errorDetails: err });
       }
    }
    

Пример должен обрабатывать как резервную проверку подлинности через MSAL, так и проверку подлинности единого входа через Office. Пример сначала попытается выполнить единый вход, а authSSO логическое значение в верхней части файла будет отслеживаться, если пример использует единый вход или переключился на резервную проверку подлинности.

Запуск проекта

  1. Убедитесь в наличии нескольких файлов в OneDrive, чтобы можно было проверить результаты.

  2. Откройте командную строку в корне папки \Begin.

  3. Выполните команду npm install , чтобы установить все зависимости пакета.

  4. Выполните команду npm start , чтобы запустить сервер среднего уровня.

  5. Вам потребуется загрузить неопубликованную надстройку в приложение Office (Excel, Word или PowerPoint), чтобы протестировать ее. Инструкции зависят от вашей платформы. Ссылки на инструкции доступны в разделе Загрузка неопубликованной надстройки Office для тестирования.

  6. В приложении Office на вкладке ленты Главная нажмите кнопку Показать надстройку в группе Единый вход Node.js, чтобы открыть надстройку области задач.

  7. Нажмите кнопку Получить имена файлов OneDrive. Если вы вошли в Office с помощью Microsoft 365 для образования или рабочей учетной записи или учетной записи Майкрософт и единый вход работает должным образом, первые 10 имен файлов и папок в вашем OneDrive для бизнеса вставляются в документ. (Первый раз может занять до 15 секунд.) Если вы не вошли в систему или находитесь в сценарии, который не поддерживает единый вход, или единый вход не работает по какой-либо причине, вам будет предложено войти. После входа отображаются имена файлов и папок.

Примечание.

Если вы ранее выполняли вход в Office с использованием другого идентификатора и все еще не закрыли некоторые из открытых тогда приложений Office, Office может не сменить идентификатор (даже если кажется, что это сделано). Если это произойдет, возможен сбой при вызове Microsoft Graph или возврат данных для другого идентификатора. Чтобы избежать этого, закройте все приложения Office, прежде чем нажимать кнопку Получить имена файлов OneDrive.

Заметки о безопасности

  • Маршрут /getuserfilenames в getFilesroute.js использует литеральную строку для создания вызова Microsoft Graph. Если вы измените вызов таким образом, что какая-либо часть строки поступает из входных данных пользователя, очистите входные данные, чтобы их нельзя было использовать при атаке внедрения заголовка ответа.

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

    "Content-Security-Policy": "script-src https://appsforoffice.microsoft.com https://ajax.aspnetcdn.com https://alcdn.msauth.net " + process.env.SERVER_SOURCE,

Всегда следуйте рекомендациям по обеспечению безопасности в документации по платформа удостоверений Майкрософт.