シングル サインオンを使用する Node.js Office アドインを作成する

ユーザーは Office にサインインできます。Office Web アドインでは、このサインイン プロセスを利用して、ユーザーに 2 回目のサインインを要求することなく、アドインと Microsoft Graph に対するユーザーの承認を行うことができます。 概要については、「Office アドインで SSO を有効化する」を参照してください。

この記事では、アドインでシングル サインオン (SSO) を有効にするプロセスについて説明します。 作成するサンプル アドインには 2 つの部分があります。Microsoft Excel に読み込まれる作業ウィンドウと、作業ウィンドウの Microsoft Graph への呼び出しを処理する中間層サーバー。 中間層サーバーは、Node.js と Express を使用して構築され、 /getuserfilenamesユーザーの OneDrive フォルダー内の最初の 10 個のファイル名の一覧を返す 1 つの REST API を公開します。 作業ウィンドウでは、 メソッドを getAccessToken() 使用して、中間層サーバーにサインインしているユーザーのアクセス トークンを取得します。 中間層サーバーは、On-Behalf-Of フロー (OBO) を使用して、Microsoft Graph にアクセスできる新しいサーバーのアクセス トークンを交換します。 このパターンを拡張して、任意の Microsoft Graph データにアクセスできます。 作業ウィンドウでは、Microsoft Graph サービスが必要なときに、常に中間層 REST API を呼び出します (アクセス トークンを渡します)。 中間層は、OBO によって取得されたトークンを使用して Microsoft Graph サービスを呼び出し、結果を作業ウィンドウに返します。

この記事では、Node.js と Express を使用するアドインを使用します。 ASP.NET ベースのアドインに関する同様の記事については、「シングル サインオンを使用する ASP.NET Office アドインを作成する」を参照してください。

前提条件

  • Node.js (最新 LTS バージョン)

  • Git バッシュ (またはその他の Git クライアント)

  • コード エディター - Visual Studio Code をお勧めします

  • Microsoft 365 サブスクリプションのOneDrive for Businessに保存されている少なくともいくつかのファイルとフォルダー

  • IdentityAPI 1.3 要件セットをサポートする Microsoft 365 のビルド。 Microsoft 365 開発者プログラムを通じて、開発者サンドボックスを含むMicrosoft 365 E5開発者サブスクリプションの対象となる場合があります。詳細については、「FAQ」を参照してください。 開発者サンドボックスには、この記事の後の手順でアプリの登録に使用できる Microsoft Azure サブスクリプションが含まれています。 必要に応じて、アプリの登録に別の Microsoft Azure サブスクリプションを使用できます。 Microsoft Azure で試用版サブスクリプションを取得します。

スタート プロジェクトをセットアップする

  1. Office Add-in NodeJS SSO」にあるリポジトリを複製するかダウンロードします。

    注:

    サンプルには 2 つのバージョンがあります。

    • Begin フォルダーはスターター プロジェクトです。 SSO や承認に直接関連しない UI などの側面は、既に完了しています。 この記事で後述する各セクションでは、これを完成させるための手順を順に説明します。
    • Complete フォルダーには、この記事のすべてのコーディング手順が完了した同じサンプルが含まれています。 完成したバージョンを使用するには、この記事の手順に従うだけですが、"Begin" を "Complete" に置き換え、「 クライアント側のコーディング 」と「 中間層サーバー側のコーディング 」のセクションをスキップします。
  2. [開始] フォルダーでコマンド プロンプトを開きます。

  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

アドインを Microsoft ID プラットフォーム に登録する

Web サーバーを表すアプリ登録を Azure で作成する必要があります。 これにより、JavaScript のクライアント コードに対して適切なアクセス トークンを発行できるように、認証のサポートが可能になります。 この登録では、クライアントでの SSO と、Microsoft 認証ライブラリ (MSAL) を使用したフォールバック認証の両方がサポートされます。

  1. Microsoft 365 テナントへの管理者資格情報を使用して、Azure portalにサインインします。 たとえば、「 MyName@contoso.onmicrosoft.com 」のように入力します。

  2. [アプリの登録] を選択します。 アイコンが表示されない場合は、検索バーで "アプリの登録" を検索します。

    Azure portalホーム ページ。

    [アプリの登録] ページが表示されます。

  3. [新規登録] を選択します。

    [アプリの登録] ウィンドウでの新しい登録。

    [アプリケーション登録] ページが表示されます。

  4. [アプリケーションを登録] ページで、次のように値を設定します。

    • <add-in-name>[名前] を設定します。
    • [サポートされているアカウントの種類] を[任意の組織のディレクトリ (任意の Azure AD ディレクトリ - マルチテナント)] と個人用 Microsoft アカウント (Skype、Xbox など) に設定します。
    • プラットフォームシングルページ アプリケーション (SPA)URI を 使用するようにリダイレクト URI を にhttps://<fully-qualified-domain-name>/dialog.html設定します。

    名前とサポートされているアカウントが完了したアプリケーション ウィンドウを登録します。

  5. [登録] を選択します。 アプリケーション登録が作成されたことを示すメッセージが表示されます。

    アプリケーションの登録が作成されたことを示すメッセージ。

  6. アプリケーション (クライアント) ID とディレクトリ (テナント) ID の値をコピーして保存します。 以降の手順では、それらの両方を使用します。

    クライアント ID とディレクトリ ID を表示する Contoso のアプリ登録ウィンドウ。

クライアント シークレットを追加する

アプリケーション パスワードと呼ばれることもあります。クライアント シークレットは、証明書の代わりにアプリが ID 自体に使用できる文字列値です。

  1. 左側のウィンドウで、[ 証明書 & シークレット] を選択します。 次に、[ クライアント シークレット ] タブで、[ 新しいクライアント シークレット] を選択します。

    [証明書 & シークレット] ウィンドウ。

    [ クライアント シークレットの追加] ウィンドウが表示されます。

  2. クライアント シークレットの説明を追加します。

  3. シークレットの有効期限を選択するか、カスタム有効期間を指定します。

    • クライアント シークレットの有効期間は、2 年間 (24 か月) 以下に制限されます。 24 か月を超えるカスタム有効期間を指定することはできません。
    • Microsoft では、有効期限の値を 12 か月未満に設定することをお勧めします。

    説明と有効期限が完了したクライアント シークレット ウィンドウを追加します。

  4. [追加] を選択します。 新しいシークレットが作成され、値が一時的に表示されます。

重要

クライアント アプリケーション コードで使用するシークレットの値を記録します。 このウィンドウを離れた後、このシークレット値は 再び表示されることはありません

Web API を公開する

  1. 左側のウィンドウで、[ API の公開] を選択します。

    [ API の公開 ] ウィンドウが表示されます。

    アプリ登録の [API の公開] ウィンドウ。

  2. [ 設定] を選択して、アプリケーション ID URI を生成します。

    アプリ登録の [API の公開] ウィンドウの [設定] ボタン。

    アプリケーション ID URI を設定するためのセクションは、 形式 api://<app-id>で生成されたアプリケーション ID URI と共に表示されます。

  3. アプリケーション ID URI を に更新します api://<fully-qualified-domain-name>/<app-id>

    localhost ポートが 44355 に設定されている [アプリ ID URI] ペインを編集します。

    • アプリケーション ID URI には、アプリ ID (GUID) が形式 api://<app-id> で事前に入力されています。
    • アプリケーション ID URI 形式は次のとおりです。 api://<fully-qualified-domain-name>/<app-id>
    • <app-id> (fully-qualified-domain-nameGUID) の間api://に を挿入します。 たとえば、「 api://contoso.com/<app-id> 」のように入力します。
    • localhost を使用している場合、形式は である api://localhost:<port>/<app-id>必要があります。 たとえば、「 api://localhost:3000/c6c1f32b-5e55-4997-881a-753cc1d563b7 」のように入力します。

    その他のアプリケーション ID URI の詳細については、「 アプリケーション マニフェスト識別子Uris 属性」を参照してください。

    注:

    ドメインを所有しているにもかかわらず、そのドメインが既に所有されているというエラーが表示される場合は、「クイック スタート: カスタム ドメイン名を Azure Active Directory に追加する」の手順に従って登録し、この手順を繰り返します。 (このエラーは、Microsoft 365 テナントの管理者の資格情報でサインインしていない場合にも発生する可能性があります。手順 2 を参照してください。サインアウトし、管理者の資格情報を使用してもう一度サインインし、手順 3. のプロセスを繰り返します)。

スコープを追加する

  1. [ API の公開 ] ページで、[ スコープの追加] を選択します。

    [スコープの追加] ボタンを選択します。

    [ スコープの追加] ウィンドウが開きます。

  2. [ スコープの追加] ウィンドウで、スコープ の属性を指定します。 次の表は、および のアクセス許可を必要とするおよび Outlook アドインの値のprofileopenidFiles.ReadWrite例をMail.Read示しています。 アドインに必要なアクセス許可に合わせてテキストを変更します。

    フィールド 説明
    スコープ名 スコープの名前。 一般的なスコープの名前付け規則は です resource.operation.constraint SSO の場合、これは に設定する access_as_user必要があります。
    同意できるユーザー 管理者の同意が必要かどうか、またはユーザーが管理者の承認なしで同意できるかどうかを決定します。 SSO とサンプルを学習するには、これを [管理者とユーザー] に設定することをお勧めします。

    高い特権を持つアクセス許可 の場合にのみ、[管理者] を選択します。
    同意の表示名管理 スコープの目的の簡単な説明は、管理者にのみ表示されます。 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 の公開] ウィンドウに表示される新しいスコープ。

    注:

    テキスト フィールドのすぐ下に表示される [スコープ名] のドメイン部分は、たとえば api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user のように手順で設定された [アプリケーション ID URI] と自動的に一致し、最後に /access_as_user が追加されます。

  4. [クライアント アプリケーションの追加] を選択します。

    [クライアント アプリケーションの追加] を選択します。

    [ クライアント アプリケーションの追加] ウィンドウが表示されます。

  5. [クライアント ID] に「」と入力しますea5a67f6-b6f3-4338-b240-c655ddc3cc8e。 この値は、すべての Microsoft Office アプリケーション エンドポイントを事前に承認します。 また、Microsoft Teams 内で使用するときに Office を事前に承認する場合は、(Microsoft Teams デスクトップと Teams モバイル) と 5e3ce6c0-2b1f-4285-8d4b-75ee78787346 (Teams on the web) を追加1fec8e78-bce4-4aaf-ab1b-5451cc387264します。

    注:

    ID は ea5a67f6-b6f3-4338-b240-c655ddc3cc8e 、次のすべてのプラットフォームで Office を事前に承認します。 または、何らかの理由で一部のプラットフォームで Office への承認を拒否する場合は、次の ID の適切なサブセットを入力することもできます。 その場合は、承認を保留するプラットフォームの ID を除外します。 これらのプラットフォーム上のアドインのユーザーは Web API を呼び出せなくなりますが、アドイン内の他の機能は引き続き機能します。

    • d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office)
    • 93d53678-613d-4013-afc1-62e9e444a0a5 (Office on the web)
    • bc59ab01-8403-45c6-8796-ac3ef710b3e3 (Outlook on the web)
  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 アドインの場合、および Mail.Readを使用Files.ReadWriteprofileopenidできます。

    注:

    User.Read アクセス許可は既定でリストされています。 必要なアクセス許可のみを要求することをお勧めします。アドインで実際に必要ない場合は、このアクセス許可のチェック ボックスをオフにすることをお勧めします。

  6. 表示される各アクセス許可のチェック ボックスをオンにします。 アクセス許可は、各アクセス許可を選択しても一覧に表示されません。 アドインに必要なアクセス許可を選択したら、[ アクセス許可の追加] を選択します。

    一部のアクセス許可が選択されている [API のアクセス許可の要求] ウィンドウ。

  7. [ テナント名] の [管理者の同意の付与] を選択します。 表示される確認のために [ はい ] を選択します。

アクセス トークンのバージョンを構成する

アプリで許容されるアクセス トークンのバージョンを定義する必要があります。 この構成は、Azure Active Directory アプリケーション マニフェストで行われます。

アクセス トークンのバージョンを定義する

アクセス トークンのバージョンは、 任意の組織ディレクトリ (任意の Azure AD ディレクトリ - マルチテナント) と個人用 Microsoft アカウント (Skype、Xbox など) のアカウントの種類以外を選択した場合に変更される可能性があります。 次の手順を使用して、アクセス トークンのバージョンが Office SSO の使用に適していることを確認します。

  1. 左側のウィンドウで、[マニフェスト] を選択 します

    [Azure マニフェスト] を選択します。

    Azure Active Directory アプリケーション マニフェストが表示されます。

  2. accessTokenAcceptedVersion プロパティの値として 2 を入力します。

    受け入れられたアクセス トークンのバージョンの値。

  3. [保存] を選択します。

    マニフェストが正常に更新されたことを示すメッセージがブラウザにポップアップ表示されます。

    マニフェストが更新されたメッセージ。

おめでとうございます! アプリの登録を完了して、Office アドインの SSO を有効にしました。

アドインを構成する

  1. コード エディターで複製プロジェクトの\Beginフォルダーを開きます。

  2. ファイルを .ENV 開き、 Office-Add-in-NodeJS-SSO アプリの登録から前にコピーした値を使用します。 次のように値を設定します。

    名前
    CLIENT_ID アプリ登録の概要ページからのアプリケーション (クライアント) 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 アプリ登録の作成時にコピーしたアプリケーション ID に置き換えます。 "$" 記号は ID の一部ではないため、含めないでください。 これは、 のCLIENT_IDに使用した ID と同じです。ENV ファイル。

    注:

    [<リソース]> の値は、アドインを登録したときに設定したアプリケーション ID URI です。 [<スコープ]> セクションは、アドインが AppSource で販売されている場合にのみ同意ダイアログ ボックスを生成するために使用されます。

  5. \public\javascripts\fallback-msal\authConfig.js ファイルを開きます。 プレースホルダー "$app-id-guid$" を、前に作成した Office-Add-in-NodeJS-SSO アプリ登録から保存したアプリケーション ID に置き換えます。

  6. 変更をファイルに保存します。

クライアント側のコーディング

Web サーバー REST API を呼び出す

  1. コード エディターで、public\javascripts\ssoAuthES6.jsファイルを開きます。 これには、Trident (Internet エクスプローラー 11) Webview コントロールでも Promise が確実にサポートされるようにするコードとOffice.onReady、アドインの唯一のボタンにハンドラーを割り当てる呼び出しが既に用意されています。

    注:

    名前が示すように、ssoAuthES6.js は JavaScript ES6 構文を使用します。これは、これは、asyncawaitの使用こそが SSO API の本質的なシンプルさを最もよく示すためです。 localhost サーバーが起動されると、このファイルは ES5 構文に変換され、サンプルで Trident がサポートされます。

  2. getFileNameList 関数で、TODO 1 を次のコードに置き換えます。 このコードについては、以下の点に注意してください。

    • この関数 getFileNameList は、ユーザーが作業ウィンドウで [ OneDrive ファイル名の取得 ] ボタンを選択すると呼び出されます。
    • 呼び出す callWebServerAPI REST API を指定する関数を呼び出します。 これにより、ユーザーの OneDrive からのファイル名の一覧を含む JSON が返されます。
    • 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 を次のコードに置き換えます。 このコードについては、以下の点に注意してください。

    • 関数は、トークンを取得するために必要に応じて Office SSO または MSAL フォールバックを使用してカプセル化する独自の関数を呼び出 getAccessToken します。 null トークンを返す場合、解決できない認証エラー条件のメッセージが表示されたため、関数も null を返します。
    • 関数は API を fetch 使用して Web サーバーを呼び出し、成功した場合は 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 を次のコードに置き換えます。 このコードについては、以下の点に注意してください。

    • このコードは、SSO トークンの有効期限が切れたシナリオを処理します。 その場合は、 を呼び出 Office.auth.getAccessToken して更新されたトークンを取得する必要があります。 最も簡単な方法は、 に対して新しい呼び出しを行う再帰呼び出しを Office.auth.getAccessToken行う方法です。 パラメーターを retryRequest 使用すると、再帰呼び出しが 1 回だけ試行されます。
    • この TokenExpiredError 文字列は、期限切れのトークンを検出するたびに Web サーバーによって設定されます。
     // 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 呼び出しが失敗するたびに Web サーバーによって設定されます。
    // 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 は、SSO を使用している場合、または MSAL フォールバックを使用している場合は追跡されます。 SSO が使用されている場合、関数は トークンを呼び出 Office.auth.getAccessToken して返します。
    • エラーは関数によって handleSSOErrors 処理され、フォールバック MSAL 認証に切り替えた場合にトークンが返されます。
    • フォールバック認証では、MSAL ライブラリを使用してユーザーにサインインします。 アドイン自体は SPA であり、SPA アプリの登録を使用して Web サーバーにアクセスします。
    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 アドインの SSO のトラブルシューティング (Troubleshoot SSO in Office Add-ins)」を参照してください。

    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.
    

Web サーバー REST API をコーディングする

Web サーバーは、クライアントが呼び出す REST API を提供します。 たとえば、REST API /getuserfilenames は、ユーザーの OneDrive フォルダーからファイル名の一覧を取得します。 各 REST API 呼び出しでは、正しいクライアントがデータにアクセスしていることを確認するために、クライアントによるアクセス トークンが必要です。 アクセス トークンは、On-Behalf-Of フロー (OBO) を介して Microsoft Graph トークンと交換されます。 新しい Microsoft Graph トークンは、後続の API 呼び出しのために MSAL ライブラリによってキャッシュされます。 Web サーバーの外部に送信されることはありません。 詳細については、「中間層のアクセス トークン要求」を参照してください。

ルートを作成し、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 を使用して への呼び出し acquireTokenOnBehalfOfで OBO フローを実行します。
    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 を次のコードに置き換えます。 このコードについては、以下の点に注意してください。

    • Microsoft Graph API 呼び出しの URL を構築し、関数を介して呼び出しを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 経由の SSO 認証の両方を処理する必要があります。 サンプルでは最初に SSO を試し、サンプルが SSO を authSSO 使用している場合、またはフォールバック認証に切り替えた場合は、ファイルの上部にあるブール値が追跡されます。

プロジェクトを実行する

  1. 結果を確認できるように、OneDrive 内にファイルがいくつかあることを確認します。

  2. \Beginフォルダーのルートでコマンド プロンプトを開きます。

  3. コマンドを実行して、すべてのパッケージの依存関係をインストールします npm install

  4. コマンド npm start を実行して中間層サーバーを起動します。

  5. アドインを Office アプリケーション (Excel、Word、または PowerPoint) にサイドロードして、テストをする必要があります。 手順はプラットフォームによって異なります。 「テスト用に Office アドインをサイドロードする」に手順へのリンクがあります。

  6. Office アプリケーションの [ホーム] リボンで [アドインの表示] ボタン (SSO Node.js グループ内) を選択して、作業ウィンドウ アドインを開きます。

  7. [OneDrive ファイル名の取得] ボタンをクリックします。 Microsoft 365 Educationまたは職場アカウント、または Microsoft アカウントを使用して Office にログインしていて、SSO が正常に動作している場合は、OneDrive for Business内の最初の 10 個のファイル名とフォルダー名がドキュメントに挿入されます。 (初回は 15 秒ほどかかる場合があります。ログインしていない場合、または SSO をサポートしていないシナリオや、何らかの理由で SSO が機能しない場合は、サインインするように求められます。 サインインすると、ファイル名とフォルダー名が表示されます。

注:

以前に別の ID で Office にサインインしており、その時点で開いていた一部の Office アプリケーションがまだ開いている場合、Office が ID を変更したかのように見えても、確実に ID を変更できていない場合があります。 これが発生すると、Microsoft Graph の呼び出しが失敗するか、以前の ID のデータが返される場合があります。 これを防ぐには、必ず他のすべての Office アプリケーションを閉じてから、[OneDrive ファイル名の取得] を押してください。

セキュリティに関する注意事項

  • getFilesroute.jsルートでは/getuserfilenames、リテラル文字列を使用して 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,

Microsoft ID プラットフォームドキュメントのセキュリティのベスト プラクティスに常に従ってください。