Использование единого входа в надстройках Office с Помощью Microsoft Graph

Завершено

Пользователи входят в Office (в Интернете, на мобильных устройствах и настольных компьютерах), используя личную учетную запись Майкрософт, учетную запись Microsoft 365 для образования или рабочую учетную запись.

Чтобы надстройка Office могла получить авторизованный доступ к Microsoft Graph, лучше всего использовать учетные данные для входа пользователя в Office. Это позволяет пользователям получить доступ к своим данным Microsoft Graph без необходимости повторного входа.

В этом блоке вы узнаете, как реализовать единый вход в надстройке Office для отправки запросов и получения информации из Microsoft Graph.

Надстройки Office, единый вход и Microsoft Graph

Для начала рассмотрим, как работает поток проверки подлинности во время выполнения, когда надстройка Office реализует единый вход с конечной целью для доступа к Microsoft Graph.

Обзорная схема потока проверки подлинности единого входа с надстройками Office и Microsoft Graph.

  1. В надстройке JavaScript вызывает метод API Office.js getAccessToken(). Этот метод указывает клиентскому приложению Office, что необходимо получить маркер доступа к надстройке.

    Примечание.

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

  2. Если вход в Office не выполнен, в клиентском приложении открывается всплывающее окно, в котором пользователю предлагается войти.

  3. Если пользователь запускает надстройку в первый раз, ему предлагается дать согласие.

  4. Клиентское приложение Office запрашивает маркер доступа к начальной загрузке у конечной точки Azure AD версии 2.0 для текущего пользователя.

  5. Microsoft Entra ID возвращает маркер начальной загрузки клиентскому приложению Office.

  6. Клиентское приложение Office отправляет надстройке маркер доступа к начальной загрузке в составе объекта результата, возвращенного при вызове метода getAccessToken().

  7. Код JavaScript надстройки отправляет HTTP-запрос к веб-API с тем же полным доменным именем, что и у надстройки. Этот запрос включает маркер доступа к начальной загрузке в качестве подтверждения авторизации.

  8. Серверный код проверяет полученный маркер доступа к начальной загрузке.

  9. Серверный код использует поток On-Behalf-Of (OBO) OAuth2 для получения маркера доступа для Microsoft Graph в обмен на маркер доступа к начальной загрузке.

  10. Microsoft Entra ID возвращает маркер доступа в Microsoft Graph и маркер обновления, если надстройка запрашивает разрешение offline_access, в надстройку.

  11. Серверный код кэширует маркер доступа в Microsoft Graph.

  12. Серверный код отправляет запросы к Microsoft Graph и включает маркер доступа в Microsoft Graph.

  13. Microsoft Graph возвращает данные надстройке, а она может передать их своему пользовательскому интерфейсу.

  14. Когда маркер доступа в Microsoft Graph истекает, серверный код может использовать свой маркер обновления, чтобы получить новый маркер доступа в Microsoft Graph.

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

Это может вызвать проблемы с надстройкой, поскольку она не может знать, можно ли использовать этот начальный маркер начальной загрузки в OBO OAuth2 для получения маркера доступа для вызова Microsoft Graph.

Если вашему коду требуются разрешения для Microsoft Graph или больше разрешений, на которые пользователь еще не дал согласия, то при получении маркера начальной загрузки Microsoft Graph произойдет сбой с определенным кодом ошибки: AADSTS65001. Этот код ошибки указывает на то, что согласие на запрошенные разрешения Microsoft Graph еще не предоставлено.

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

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

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

Метод getAccessToken() в пакете SDK Office.js принимает объект параметров, который можно использовать для реализации подхода с быстрым сбоем. Если передать { forMSGraphAccess: true } этот метод, Microsoft Entra ID выполнит дополнительную проверка перед возвратом маркера начальной загрузки.

Если пользователь разрешил запрашивать разрешения Microsoft Graph, надстройка получит маркер начальной загрузки, который можно использовать для обмена с Microsoft Graph с помощью потока OBO OAuth2 для получения маркера доступа, который можно использовать для вызова Microsoft Graph.

Однако если пользователь не дал согласие на запрошенные разрешения Microsoft Graph, Microsoft Entra ID ответит ошибкой 13012. Код может обработать эту ошибку, вернувшись к альтернативной системе авторизации. В этом альтернативном процессе откроется диалоговое окно и пользователю будет предложено дать согласие на необходимые разрешения Microsoft Graph.

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

Код в проекте единого входа надстройки Office по умолчанию включает шаблонный код, необходимый для реализации этого резервного процесса авторизации. Все они находятся в виде файлов ./helpers/fallbackauth*.* , коллекции файлов HTML и JavaScript, которые реализуют всплывающее диалоговое окно.

Вызов Microsoft Graph из клиентского кода

Чтобы отправить запрос в Microsoft Graph, необходимо сначала вызвать метод getAccessToken() следующим образом. В этом примере мы переходим к параметру allowSignInPrompt: true, который можно использовать, если надстройка может использоваться при запуске надстройки, когда выполнивший вход пользователь отсутствует.

const sso = require("office-addin-sso");

// ...

let bootstrapToken = await OfficeRuntime.auth.getAccessToken({ allowSignInPrompt: true });

Снимок экрана: вход в Word.

Затем вы попытаемся обменять этот маркер начальной загрузки на маркер доступа, который можно использовать для вызова Microsoft Graph. Именно эта часть запускает поток OBO OAuth2:

let exchangeResponse = await sso.getGraphToken(bootstrapToken);

Предположим, что пользователь дал согласие на необходимые разрешения Microsoft Graph, вы можете запросить сведения о профиле пользователя из Microsoft Graph, вызывая метод makeGraphApiCall(), включенный в предоставленный пакет JavaScript office-addin-sso:

const response = await sso.makeGraphApiCall(exchangeResponse.access_token);

Если вам нужен больший контроль над запросом к Microsoft Graph, включая вызов определенной конечной точки или предоставление большего контроля над параметрами URL-адреса, можно использовать метод getGraphData():

const endpoint = "/me/messages";
const urlParams = "?$select=receivedDateTime,subject,isRead&$orderby=receivedDateTime&$top=10";
const response = await sso.getGraphData(exchangeResponse.access_token, endpoint, urlParams);

Как упоминалось ранее, если пользователь не предоставил согласие Microsoft Graph на необходимые разрешения или ему нужно выполнить вход, все упомянутые ранее фрагменты кода можно упаковать в блок, обрабатывающий try-catch ошибки проверки подлинности и авторизации, возвращаемые Microsoft Entra ID. В таких случаях будет реализована система диалогов резервной авторизации:

const fallbackAuthHelper = require("./fallbackAuthHelper");

// ...

try {
  // 1. get bootstrap token
  // 2. exchange bootstrap token for access token
  // 3. call Microsoft Graph
} catch (exception) {
  if (exception.code) {
    if (sso.handleClientSideErrors(exception)) {
      fallbackAuthHelper.dialogFallback();
    }
  } else {
    sso.showMessage("EXCEPTION: " + JSON.stringify(exception));
  }
}