SharePoint Framework で Microsoft Graph を実行する

SharePoint Framework のクライアント側 Web パーツまたは拡張機能から、Azure Active Directory (Azure AD) と Open Authorization (OAuth 2.0) でセキュリティ保護された REST API を実行することが、エンタープライズレベルの一般的なビジネス シナリオです。

v1.4.1で導入された SharePoint Framework を使用して、Microsoft Graph REST API、または Azure AD に登録されているその他の REST API を使用できます。

この記事では、Microsoft Graph API とカスタムのアクセス許可セットを使用する SharePoint Framework ソリューションを作成する方法を学習します。 このテクノロジの概念については、「SharePoint Framework ソリューションでの Azure AD で保護された API への接続」を参照してください。

重要

ネイティブ GraphHttpClient を使用するか、Microsoft ID platfomr 認証ライブラリの暗黙的な OAuth フローを直接使用して、v1.4.1 より前のバージョンのSharePoint Frameworkで Microsoft Graph APIを使用できます。 しかし、前者のアプローチは、事前定義された一連のアクセス許可にバインドされているため、いくらかの制限があります。一方、後者は開発の観点からすると複雑です。 OAuth の暗黙的フローの実装方法については、「Azure Active Directory でセキュリティ保護された API への接続」を参照してください。

ソリューションの概要

この記事の手順では、次のスクリーンショットに示すように、現在のテナント内のユーザーを検索できるクライアント側の Web パーツを作成する方法を示します。 検索は Microsoft Graph に基づいており、少なくとも User.ReadBasic.All アクセス許可が必要です。

テナント内のユーザーを検索するためのテキスト ボックスと検索ボタンがあるクライアント側の Web パーツ

クライアント側の Web パーツでは、ユーザーをその名前に基づいて検索すると、DetailsList Office UI Fabric コンポーネントによって、一致するユーザーが表示されます。 Web パーツのプロパティ ウィンドウには、Microsoft Graph へのアクセス方法を選択するオプションがあります。 SharePoint Framework v.1.4.1 以降のバージョンで、ネイティブのグラフ クライアント (MSGraphClient)、または任意の Azure AD でセキュリティ保護された REST API (AadHttpClient) へのアクセスに使用する低レベル タイプのどちらかを使用して、Microsoft Graph にアクセスすることができます。

注:

このソリューションのソース コードを入手するには、api-scopes GitHub リポジトリを参照してください。

SharePoint Framework ソリューションの作成方法を既に理解している場合は、「API アクセス許可要求を構成する」に進むことができます。

最初のソリューションの作成

SharePoint Framework ジェネレーターの以前のバージョンを使用している場合は、これを v1.4.1 以降に更新する必要があります。 それを行うには、次のコマンドを実行して、最新バージョンのパッケージをグローバルにインストールします。

npm install -g @microsoft/generator-sharepoint

次に、新しい SharePoint Framework ソリューションを作成します。

  1. ファイル システムにフォルダーを作成します。 ソリューションのソース コードを格納し、現在のパスをこのフォルダーに移動します。

  2. Yeoman ジェネレーターを実行して新しいソリューションをスキャフォールディングします

    yo @microsoft/sharepoint
    
  3. プロンプトが表示されたら、以下の値を入力します (以下で省略されたすべてのプロンプトに対して既定のオプションを選択します):

    • ソリューション名は何ですか? spfx-api-scopes-tutorial
    • どのベースライン パッケージをコンポーネントのターゲットにしたいですか? SharePoint Online のみ (最新)
    • どの種類のクライアント側コンポーネントを作成しますか? Web パーツ
    • Web パーツ名は何ですか? GraphConsumer
    • どのフレームワークを使用しますか? React
  4. Visual Studio Code (または必要なコード エディター) を現在のフォルダーのコンテキスト内で開始する。

    code .
    

基本的な Web パーツ要素の構成

次に、クライアント側の Web パーツの初期の要素を構成します。

カスタム プロパティの構成

  1. ソリューションの src/webparts/graphConsumer/components フォルダー内に新しいソース コード ファイルを作成します。

    新しいファイル ClientMode.ts を呼び出し、これを使用して TypeScript enumと、Web パーツの ClientMode プロパティに使用できるオプションを宣言します。

    export enum ClientMode {
      aad,
      graph,
    }
    
  2. ソリューションの ./src/webparts/graphConsumer フォルダーにある GraphConsumerWebPart.ts ファイルを開きます。

    ClientMode 型の値を受け入れるように、IGraphConsumerWebPartProps インターフェイスの定義を変更します。

    export interface IGraphConsumerWebPartProps {
      clientMode: ClientMode;
    }
    
  3. クライアント側の Web パーツの getPropertyPaneConfiguration() メソッドを更新し、プロパティ ウィンドウでの選択肢の選択を可能にします。 以下の例は、メソッドの新しい実装を示します。

    protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
      return {
        pages: [
          {
            header: {
              description: strings.PropertyPaneDescription
            },
            groups: [
              {
                groupName: strings.BasicGroupName,
                groupFields: [
                  PropertyPaneChoiceGroup('clientMode', {
                    label: strings.ClientModeLabel,
                    options: [
                      { key: ClientMode.aad, text: "AadHttpClient"},
                      { key: ClientMode.graph, text: "MSGraphClient"},
                    ]
                  }),
                ]
              }
            ]
          }
        ]
      };
    }
    
  4. クライアント側の Web パーツの render() メソッドを更新して、レンダリングのための React コンポーネントのインスタンスを正しい構成で作成するようにします。 以下のコードは、更新メソッドの定義を示しています。

    public render(): void {
      const element: React.ReactElement<IGraphConsumerProps > = React.createElement(
        GraphConsumer,
        {
          clientMode: this.properties.clientMode,
          context: this.context,
        }
      );
    
      ReactDom.render(element, this.domElement);
    }
    
  5. このコードを機能させるには、次の例に示すように、GraphConsumerWebPart.ts ファイルの先頭にいくつかの import ステートメントを追加する必要があります。 PropertyPaneChoiceGroup コントロールのインポート、および ClientMode 列挙型のインポートに注目してください。

    import * as React from "react";
    import * as ReactDom from "react-dom";
    import { Version } from "@microsoft/sp-core-library";
    import {
      BaseClientSideWebPart,
      IPropertyPaneConfiguration,
      PropertyPaneChoiceGroup,
    } from "@microsoft/sp-webpart-base";
    
    import * as strings from "GraphConsumerWebPartStrings";
    import GraphConsumer from "./components/GraphConsumer";
    import { IGraphConsumerProps } from "./components/IGraphConsumerProps";
    import { ClientMode } from "./components/ClientMode";
    

リソース文字列を更新する

ソリューションをコンパイルするには、ソリューションの ./src/webparts/graphConsumer/loc フォルダー内の mystrings.d.ts ファイルを更新する必要があります。

  1. リソース文字列を定義するインターフェイスを次のコードで書き換えます。

    declare interface IGraphConsumerWebPartStrings {
      PropertyPaneDescription: string;
      BasicGroupName: string;
      ClientModeLabel: string;
      SearchFor: string;
      SearchForValidationErrorMessage: string;
    }
    
  2. 同じフォルダー内の en-us.js ファイルを更新して、新しく作成したリソース文字列に正しい値を設定します。

    define([], function () {
      return {
        PropertyPaneDescription: "Description",
        BasicGroupName: "Group Name",
        ClientModeLabel: "Client Mode",
        SearchFor: "Search for",
        SearchForValidationErrorMessage: "Invalid value for 'Search for' field",
      };
    });
    

クライアント側の Web パーツのスタイルを更新する

SCSS スタイル ファイルを更新する必要もあります。

ソリューションの ./src/webparts/graphConsumer/components フォルダー内の GraphConsumer.module.scss を開きます。 .title クラスの直後に次のスタイル クラスを追加します:

.form {
  @include ms-font-l;
  @include ms-fontColor-white;
}

label {
  @include ms-fontColor-white;
}

Web パーツをレンダリングする React コンポーネントを更新する

ここで、ソリューションの ./src/webparts/graphConsumer/components フォルダー内の GraphConsumer React コンポーネントを更新できます。

  1. Web パーツの実装に必要なカスタム プロパティを受け入れるために、IGraphConsumerProps.ts ファイルを更新します。 更新された IGraphConsumerProps.ts ファイルの内容を次の例で示します。 ClientMode 列挙型定義のインポート、および WebPartContext 型のインポートに注目してください。 これは後で使用します。

    import { WebPartContext } from "@microsoft/sp-webpart-base";
    import { ClientMode } from "./ClientMode";
    
    export interface IGraphConsumerProps {
      clientMode: ClientMode;
      context: WebPartContext;
    }
    
  2. React コンポーネントの状態を保持する新しいインターフェイスを作成します。 ./src/webparts/graphConsumer/components フォルダーで新しいファイルを作成し、その名前を IGraphConsumerState.ts とします。 次にインターフェイスの定義を示します。

    import { IUserItem } from "./IUserItem";
    
    export interface IGraphConsumerState {
      users: Array<IUserItem>;
      searchFor: string;
    }
    
  3. IUserItem インターフェイスを (./src/webparts/graphConsumer/components フォルダーに保存されている IUserItem.ts というファイル内で) 定義します。 そのインターフェイスは、状態ファイルにインポートされます。 そのインターフェイスは、現在のテナントから取得され、UI の DetailsList にバインドされるユーザーのアウトラインの定義に使用されます。

    export interface IUserItem {
      displayName: string;
      mail: string;
      userPrincipalName: string;
    }
    
  4. GraphConsumer.tsx ファイルを更新します。 まず、事前に定義した種類をインポートする import ステートメントをいくつか追加します。 IGraphConsumerPropsIGraphConsumerStateClientMode、および IUserItem のインポートに注目してください。 React コンポーネントの UI のレンダリングに使用される Office UI Fabric コンポーネントのインポートもいくつかあります。

    import * as strings from "GraphConsumerWebPartStrings";
    import {
      BaseButton,
      Button,
      CheckboxVisibility,
      DetailsList,
      DetailsListLayoutMode,
      PrimaryButton,
      SelectionMode,
      TextField,
    } from "office-ui-fabric-react";
    import * as React from "react";
    
    import { AadHttpClient, MSGraphClient } from "@microsoft/sp-http";
    import { escape } from "@microsoft/sp-lodash-subset";
    
    import { ClientMode } from "./ClientMode";
    import styles from "./GraphConsumer.module.scss";
    import { IGraphConsumerProps } from "./IGraphConsumerProps";
    import { IGraphConsumerState } from "./IGraphConsumerState";
    import { IUserItem } from "./IUserItem";
    
  5. インポートの後、Office UI Fabric の DetailsList コンポーネントのための列のアウトラインを定義します。

    // Configure the columns for the DetailsList component
    let _usersListColumns = [
      {
        key: "displayName",
        name: "Display name",
        fieldName: "displayName",
        minWidth: 50,
        maxWidth: 100,
        isResizable: true,
      },
      {
        key: "mail",
        name: "Mail",
        fieldName: "mail",
        minWidth: 50,
        maxWidth: 100,
        isResizable: true,
      },
      {
        key: "userPrincipalName",
        name: "User Principal Name",
        fieldName: "userPrincipalName",
        minWidth: 100,
        maxWidth: 200,
        isResizable: true,
      },
    ];
    

    React コンポーネントの render() メソッドで分かるように、この配列は DetailsList コンポーネントの設定で使用されます。

  6. このコンポーネントを次のコードと置き換えます。

    public render(): React.ReactElement<IGraphConsumerProps> {
      return (
        <div className={ styles.graphConsumer }>
          <div className={ styles.container }>
            <div className={ styles.row }>
              <div className={ styles.column }>
                <span className={ styles.title }>Search for a user!</span>
                <p className={ styles.form }>
                  <TextField
                      label={ strings.SearchFor }
                      required={ true }
                      onChange={ this._onSearchForChanged }
                      onGetErrorMessage={ this._getSearchForErrorMessage }
                      value={ this.state.searchFor }
                    />
                </p>
                <p className={ styles.form }>
                  <PrimaryButton
                      text='Search'
                      title='Search'
                      onClick={ this._search }
                    />
                </p>
                {
                  (this.state.users != null && this.state.users.length > 0) ?
                    <p className={ styles.form }>
                    <DetailsList
                        items={ this.state.users }
                        columns={ _usersListColumns }
                        setKey='set'
                        checkboxVisibility={ CheckboxVisibility.hidden }
                        selectionMode={ SelectionMode.none }
                        layoutMode={ DetailsListLayoutMode.fixedColumns }
                        compact={ true }
                    />
                  </p>
                  : null
                }
              </div>
            </div>
          </div>
        </div>
      );
    }
    
  7. 次の例に示すように、React コンポーネント タイプの宣言を更新してコンストラクターを追加します。

    export default class GraphConsumer extends React.Component<IGraphConsumerProps, IGraphConsumerState> {
    
      constructor(props: IGraphConsumerProps, state: IGraphConsumerState) {
        super(props);
    
        // Initialize the state of the component
        this.state = {
          users: [],
          searchFor: ""
        };
      }
    

    検索条件を収集する TextField コンポーネントのための評価ルールと処理イベントがいくつかあります。 メソッドの実装を次に示します。

    これら 2 つのメソッドを GraphConsumerクラスの最後に追加します:

    private _onSearchForChanged = (event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string): void => {
    
      // Update the component state accordingly to the current user's input
      this.setState({
        searchFor: newValue,
      });
    }
    
    private _getSearchForErrorMessage = (value: string): string => {
      // The search for text cannot contain spaces
      return (value == null || value.length == 0 || value.indexOf(" ") < 0)
        ? ''
        : `${strings.SearchForValidationErrorMessage}`;
    }
    

    PrimaryButton\_search() 関数を実行し、これによって Microsoft Graph を実行するために使用するクライアントのテクノロジが決定されます。 このメソッドをGraphConsumerクラスの最後に追加します:

    private _search = (event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement | HTMLDivElement | BaseButton | Button, MouseEvent>) : void => {
      console.log(this.props.clientMode);
    
      // Based on the clientMode value search users
      switch (this.props.clientMode)
      {
        case ClientMode.aad:
          this._searchWithAad();
          break;
        case ClientMode.graph:
        this._searchWithGraph();
        break;
      }
    }
    

コンポーネントの状態の users プロパティにアイテムがある場合、DetailsList コンポーネント インスタンスが render() メソッドにレンダリングされます。

API アクセス許可要求の構成

Microsoft Graph またはその他のサード パーティ製 REST API を実行するには、OAuth の観点からのアクセス許可要件をソリューションのマニフェスト内で明示的に宣言する必要があります。

SharePoint Framework v.1.4.1 以降では、それはソリューションの config フォルダー内で、package-solution.jsonwebApiPermissionRequests プロパティを構成することによって行えます。 現在のソリューションについて、そのファイルの抜粋を次の例に示します。

webApiPermissionRequests プロパティの宣言をコピーします。

{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
  "solution": {
    "name": "spfx-api-scopes-tutorial-client-side-solution",
    "id": "841cd609-d821-468d-a6e4-2d207b966cd8",
    "version": "1.0.0.0",
    "includeClientSideAssets": true,
    "skipFeatureDeployment": true,
    "webApiPermissionRequests": [
      {
        "resource": "Microsoft Graph",
        "scope": "User.ReadBasic.All"
      }
    ]
  },
  "paths": {
    "zippedPackage": "solution/spfx-api-scopes-tutorial.sppkg"
  }
}

webApiPermissionRequest アイテムの配列である webApiPermissionRequests に注目してください。 各アイテムはアクセス許可要求の resourcescope を定義します。

resource は、アクセス許可要求を構成するリソースの名前、または ObjectId (Azure AD 内) のいずれかです。 Microsoft Graph の場合、名前は Microsoft Graph です。 ObjectId は一意ではなく、テナントごとに異なります。

scope はアクセス許可の名前、またはそのアクセス許可の一意の ID のいずれかです。 アクセス許可の名前は、API のドキュメントから入手できます。 アクセス許可の ID は、API のマニフェスト ファイルから入手できます。

注:

Microsoft Graph で利用可能なアクセス許可の一覧については、「Microsoft Graph のアクセス許可のリファレンス」を参照してください。

既定のサービス プリンシパルでは、Microsoft Graph への明示的なアクセス許可は付与されていません。 ただし、Microsoft Graph のアクセス トークンを要求すると、ユーザーに関する情報を読み取るために使用できる user_impersonation アクセス許可 (User.Read.All) を持つトークンを取得します。 テナント管理者が付与する追加のアクセス許可を要求できます。 詳細については、「SharePoint Framework ソリューションでの Azure AD で保護された API への接続」を参照してください。

User.ReadBasic.All 権限は、ユーザーを検索してdisplayNamemail、およびuserPrincipalNameを取得するのに十分です。

ソリューションをパッケージ化して展開するとき、ユーザー (または管理者) は、要求されるソリューションに対するアクセス許可を付与する必要があります。 詳細については、「ソリューションの展開とアクセス許可の付与」を参照してください。

Microsoft Graph の実行

これで、Microsoft Graph を実行するメソッドを実装できるようになりました。 次の 2 つの方法があります。

  • AadHttpClient クライアント オブジェクトを使用する
  • MSGraphClient クライアント オブジェクトを使用する

AadHttpClient クライアント オブジェクトは、REST API の実行に便利です。 これは Microsoft Graph、または他のサード パーティ (またはファースト パーティ) の REST API の実行に使用できます。

MSGraphClient クライアント オブジェクトは、Microsoft Graph のみを実行できます。 これは内部的に AadHttpClient クライアント オブジェクトを使用し、Microsoft Graph SDK の fluent 構文をサポートしています。

AadHttpClient の使用

AadHttpClient クライアント オブジェクトを使用して REST API を使用するには、context.aadHttpClientFactory.getClient() メソッドを呼び出し、ターゲット サービスの URI を指定して、AadHttpClient 型の新しいインスタンスを作成します。

作成したオブジェクトによって、次の要求を行うメソッドが提供されます。

  • get(): HTTP GET 要求を行う
  • post(): HTTP POST 要求を行う
  • fetch(): 指定された HttpClientConfiguration および IHttpClientOptions 引数に基づき、その他のあらゆる種類の HTTP 要求を行う。

これらすべてのメソッドでは、JavaScript/TypeScript の非同期開発モデルをサポートしているため、それを見込んで結果を処理することができます。

次の例は、サンプル ソリューションの \_searchWithAad() メソッドを示しています。

private _searchWithAad = (): void => {
  // Log the current operation
  console.log("Using _searchWithAad() method");

  // Using Graph here, but any 1st or 3rd party REST API that requires Azure AD auth can be used here.
  this.props.context.aadHttpClientFactory
    .getClient("https://graph.microsoft.com")
    .then((client: AadHttpClient) => {
      // Search for the users with givenName, surname, or displayName equal to the searchFor value
      return client
        .get(
          `https://graph.microsoft.com/v1.0/users?$select=displayName,mail,userPrincipalName&$filter=(givenName%20eq%20'${escape(this.state.searchFor)}')%20or%20(surname%20eq%20'${escape(this.state.searchFor)}')%20or%20(displayName%20eq%20'${escape(this.state.searchFor)}')`,
          AadHttpClient.configurations.v1
        );
    })
    .then(response => {
      return response.json();
    })
    .then(json => {

      // Prepare the output array
      var users: Array<IUserItem> = new Array<IUserItem>();

      // Log the result in the console for testing purposes
      console.log(json);

      // Map the JSON response to the output array
      json.value.map((item: any) => {
        users.push( {
          displayName: item.displayName,
          mail: item.mail,
          userPrincipalName: item.userPrincipalName,
        });
      });

      // Update the component state accordingly to the result
      this.setState(
        {
          users: users,
        }
      );
    })
    .catch(error => {
      console.error(error);
    });
}

get() メソッドは、入力引数として OData 要求の URL を取得します。 要求が成功すると、応答とともに JSON オブジェクトが返されます。

MSGraphClient の使用

Microsoft Graph をターゲットにしている場合は、さらに fluent 構文が提供される MSGraphClient クライアント オブジェクトを使用できます。

次の例は、サンプル ソリューションの _searchWithGraph() メソッドの実装を示しています。

private _searchWithGraph = () : void => {

  // Log the current operation
  console.log("Using _searchWithGraph() method");

  this.props.context.msGraphClientFactory
    .getClient()
    .then((client: MSGraphClient) => {
      // From https://github.com/microsoftgraph/msgraph-sdk-javascript sample
      client
        .api("users")
        .version("v1.0")
        .select("displayName,mail,userPrincipalName")
        .filter(`(givenName eq '${escape(this.state.searchFor)}') or (surname eq '${escape(this.state.searchFor)}') or (displayName eq '${escape(this.state.searchFor)}')`)
        .get((err, res) => {

          if (err) {
            console.error(err);
            return;
          }

          // Prepare the output array
          var users: Array<IUserItem> = new Array<IUserItem>();

          // Map the JSON response to the output array
          res.value.map((item: any) => {
            users.push( {
              displayName: item.displayName,
              mail: item.mail,
              userPrincipalName: item.userPrincipalName,
            });
          });

          // Update the component state accordingly to the result
          this.setState(
            {
              users: users,
            }
          );
        });
    });
}

context.msGraphClientFactory.getClient() メソッドを呼び出すことで、MSGraphClient 型のインスタンスを取得します。

次に、Microsoft Graph SDK の fluent API を使用して、ターゲットの Microsoft Graph エンドポイントに対して実行される OData クエリを定義します。

その結果は JSON 応答として返されるため、デコードし、型指定された結果にマッピングする必要があります。

注:

Microsoft Graph TypeScript 型を使用することにより、完全に型指定されたアプローチを使用できます。

ソリューションの展開とアクセス許可の付与

これで、ソリューションを構築、バンドル、パッケージ化、および展開する準備が整いました。

  1. gulp コマンドを実行して、ソリューションが正しくビルドされていることを確認します。

    gulp build
    
  2. 次のコマンドを実行して、ソリューションをバンドルし、パッケージ化します。

    gulp bundle
    gulp package-solution
    
  3. ターゲット テナントのアプリ カタログを参照し、ソリューション パッケージをアップロードします。 ソリューション パッケージは、使用しているソリューションの sharepoint/solution フォルダーにあります。 ソリューション パッケージは .sppkg ファイルです。 ソリューション パッケージをアップロードした後、アプリ カタログによって、次のスクリーンショットに示すようなダイアログ ボックスが表示されます。

    パッケージ ソリューションをアップロードするときのアプリ カタログ UI のスクリーンショット

    ソリューション パッケージにアクセス許可の承認が必要であることを示すメッセージが画面の下部に表示されます。 これは、package-solution.json ファイル内の webApiPermissionRequests プロパティによるものです。

  4. 最新の SharePoint Online 管理センターの左側のクイック起動メニューの [詳細設定] で、[API アクセス] メニュー項目を選択します。 次のようなページが表示されます。

    [WebApiPermission 管理] ページのスクリーンショット

    このページを使用すると、自分で (または SharePoint Online テナントの他の管理者が) 保留中のアクセス許可要求を承認または拒否することができます。 どのソリューション パッケージでどのアクセス許可が要求されているかは確認できません。アクセス許可は、テナント レベルで一意のアプリケーションに対して定義されているためです。

    注:

    テナント レベルのアクセス許可範囲が内部的に機能する方法の詳細は、「関連項目」のセクションの記事を参照してください。

  5. ソリューションの package-solution.json ファイルで要求したアクセス許可を選択し、[アクセスを承認または拒否する] を選択し、[承認] を選択します。 次のスクリーンショットは、管理 UI のパネルを示しています。

    承認プロセス中の WebApiPermission 管理ページのスクリーンショット

警告

アクセス許可 ([HTTP]:400 - [CorrelationId]) を承認しようとしたときに予期しない例外が発生した場合は、このチュートリアルの前半で指示されたように、Microsoft Graph ではなく Microsoft.Azure.AgregatorService の値を使用するように package-solution.jsonresource 属性を更新してください。 既存の要求を拒否し、アプリ カタログのソリューション パッケージを更新値で更新します。

ソリューションのテスト

  1. 次の gulp コマンドを使用してソリューションを実行します。

    gulp serve --nobrowser
    
  2. ブラウザーを開き、次の URL に移動し、SharePoint Framework ワークベンチのページに移動します。

    https://<your-tenant>.sharepoint.com/_layouts/15/Workbench.aspx
    
  3. クライアント側の Web パーツ GraphConsumer を追加し、[クライアント モード] を構成してユーザーを検索します。

    最初の要求を行うと、ポップアップ ウィンドウが表示され、非表示になります。 これは ADAL JS で使用されるサインイン ウィンドウであり、OAuth 暗黙的フローを使用して Azure AD からアクセス トークンを取得するために、SharePoint Framework によって内部的に使用されます。

    サンプル アプリケーションの UI のスクリーンショット

これで完了です。 これで、Azure AD で保護された REST API を使用するエンタープライズ レベルのソリューションをビルドできるようになりました。

関連項目