シングル サインオンを使用する ASP.NET Office アドインを作成する (プレビュー)Create an ASP.NET Office Add-in that uses single sign-on (preview)

ユーザーが Office にサインインしたとき、アドインは同じ資格情報を使用し、再度のサインインを要求することなく、複数のアプリケーションへのアクセスを許可することができます。概要については、「Office アドインで SSO を有効化する」を参照してください。When users are signed in to Office, your add-in can use the same credentials to permit users to access multiple applications without requiring them to sign in a second time. For an overview, see Enable SSO in an Office Add-in.

この記事では、.NET 対応の ASP.NET、OWIN、および Microsoft 認証ライブラリ (MSAL) を使用して作成したアドインで、シングル サインオン (SSO) を有効化するプロセスについて手順を追って説明します。This article walks you through the process of enabling single sign-on (SSO) in an add-in that is built with ASP.NET, OWIN, and Microsoft Authentication Library (MSAL) for .NET.

注意

Node.js ベースのアドインに関する同様の記事については、「シングル サインオンを使用する Node.js Office アドインを作成する」を参照してください。For a similar article about a Node.js-based add-in, see Create a Node.js Office Add-in that uses single sign-on.

前提条件Prerequisites

  • 入手可能な Visual Studio 2017 プレビューの最新バージョン。The latest available version of Visual Studio 2017 Preview.

  • Office 2016 バージョン 1708、ビルド 8424.nnnn 以降 (「クイック実行」と呼ばれることもある Office 365 のサブスクリプション バージョン)。このバージョンを入手するには、Office Insider への参加が必要になることがあります。詳細については、「Office Insider」を参照してください。Office 2016, Version 1708, build 8424.nnnn or later (the Office 365 subscription version, sometimes called “Click to Run”). You might need to be an Office Insider to get this version. For more information, see Be an Office Insider.

スタート プロジェクトをセットアップするSet up the starter project

  1. Office Add-in ASPNET SSO」にあるリポジトリを複製するかダウンロードします。Clone or download the repo at Office Add-in ASPNET SSO.

  2. [Before] フォルダーを開いて、Visual Studio で .sln ファイルを開きます。これがスタート プロジェクトになります。SSO や承認に直接関連しない UI などの側面は、既に完了しています。Open the Before folder and open the .sln file in Visual Studio. This is a starter project. The UI and other aspects of the add-in that are not directly connected to SSO or authorization are already done.

    注意

    同じリポジトリ内には、サンプルの完成版も含まれています。これは、この記事の手順を完了したときに得られるアドインと同様のものですが、完成済みのプロジェクトには、この記事のテキストと重複するコード コメントが含まれています。完成版を使用する場合は、sln ファイルを開いて、この記事の手順をそのまま実行しますが、「クライアント側のコードを作成する」と「サーバー側のコードを作成する」のセクションは省略してください。There is also a completed version of the sample in the same repo. It is just like the add-in that you would have if you completed the procedures in this article, except that the completed project has code comments that would be redundant with the text of this article. To use the completed version, just open the sln file and follow the instructions in this article, but skip the sections Code the client side and Code the server side.

  3. プロジェクトを開いたら、そのプロジェクトを Visual Studio でビルドします。その結果として、packages.config ファイルにリストされたパッケージがインストールされます。コンピューターのローカル パッケージ キャッシュに含まれるパッケージの数に応じて、数秒から数分の時間がかかります。After the project opens, build it in Visual Studio, which will install the packages listed in the packages.config file. This can take a few seconds to several minutes depending on how many of the packages are in the computer's local package cache.

    注意

    ID 名前空間に関するエラーが表示されます。You will get an error about the Identity namespace. これは構成の問題の副作用ですが、次のステップで修正します。This is a side effect of a configuration issue that you will fix with the next step. 重要な点は、パッケージがインストールされていることです。The important thing is that the packages are installed.

  4. 現在、SSO (バージョン 1.1.4-preview0002) に必要な MSAL ライブラリ (Microsoft.Identity.Client) は標準の nuget カタログの一部ではないため、package.config にはリストされていません。これは、個別にインストールする必要があります。Currently, the version of the MSAL library (Microsoft.Identity.Client) that you need for SSO (version 1.1.4-preview0002) is not part of the standard nuget catalog, so it is not listed in the package.config, and it must be installed separately.

    1. [ツール] メニューで [Nuget パッケージ マネージャー] > [パッケージ マネージャー コンソール] に移動します。On the Tools menu, navigate to Nuget Package Manager > Package Manager Console.

    2. コンソールで、次のコマンドを実行します。At the console, run the following command. これは高速インターネット接続の場合でも、完了までに数分かかることがあります。It may take a minute or more to complete even with a fast Internet connection. 完了すると、コンソールの出力の末尾に「'Microsoft.Identity.Client 1.1.4-alpha0002' が正常にインストールされました...」というメッセージが表示されます。When it finishes you should see Successfully installed 'Microsoft.Identity.Client 1.1.1-alpha0393' ... near the end of the output in the console.

      Install-Package Microsoft.Identity.Client -Version 1.1.4-preview0002

    3. ソリューション エクスプローラー[参照] を右クリックします。Microsoft.Identity.Client がリストされていることを確認します。リストされていない場合やエントリに警告アイコンが表示されている場合は、エントリを削除してから Visual Studio 参照の追加ウィザードを使用して、... [Begin | Complete]\packages\Microsoft.Identity.Client.1.1.1-alpha0393\lib\net45\Microsoft.Identity.Client.dll のアセンブリへの参照を追加します。In Solution Explorer, right-click References. Verify that Microsoft.Identity.Client is listed. If it is not or there is a warning icon on its entry, delete the entry and then use the Visual Studio Add Reference wizard to add a reference to the assembly at ... [Begin | Complete]\packages\Microsoft.Identity.Client.1.1.4-preview0002\lib\net45\Microsoft.Identity.Client.dll

  5. もう一度プロジェクトをビルドします。Build the project a second time.

Azure AD v2.0 エンドポイントにアドインを登録するRegister the add-in with Azure AD v2.0 endpoint

次の手順は、複数の場所で使用できるように一般的に記述されています。The following instruction are written generically so they can be used in multiple places. この記事では、以下を実行します:For this ariticle do the following:

  • プレースホルダー $ ADD-IN-NAME $Office-Add-in-ASPNET-SSO に置き換えます。Replace the placeholder $ADD-IN-NAME$ with Office-Add-in-ASPNET-SSO.
  • プレースホルダー $ FQDN-WITHOUT-PROTOCOL$localhost:44355 に置き換えます。Replace the placeholder $FQDN-WITHOUT-PROTOCOL$ with localhost:44355.
  • アクセス許可を選択 ダイアログでアクセス許可を指定するときに、次のアクセス許可のボックスをオンにします。When you specify permissions in the Select Permissions dialog, check the boxes for the following permissions. 実際にアドイン自体に必要なのは最初のものだけですが、サーバー側コードで使用される MSAL ライブラリで offline_access および openid が必要とされます。Only the first is really required by your add-in itself; but the MSAL library that the server-side code uses requires offline_access and openid. Office ホストがアドインの Web アプリケーションに対してトークンを取得するために、profile のアクセス許可が必要です。The profile permission is required for the Office host to get a token to your add-in web application.
    • Files.Read.AllFiles.Read.All
    • offline_accessoffline_access
    • openidopenid
    • プロフィールprofile
  1. https://apps.dev.microsoft.com/にナビゲートします。Navigate to https://apps.dev.microsoft.com/

  2. ダイアログが表示されたら、*** 管理者*** の資格情報を使用して Office 365 テナントにサインインします。Sign-in with the admin credentials to your Office 365 tenancy. For example, MyName@contoso.onmicrosoft.com たとえば、MyName@contoso.onmicrosoft.com のようにしますFor example, MyName@contoso.onmicrosoft.com

  3. [アプリの追加] をクリックします。Click Add an app.

  4. 表示されたら、[$ADD-IN-NAME$] をアプリ名として入力してから [アプリケーションの作成] をクリックします。When prompted, use “Office-Add-in-ASPNET-SSO” as the app name, and then press Create application.

  5. アプリの構成ページが開いたら、[アプリケーション ID] をコピーして保存します。これは、この後の手順で使用します。When the configuration page for the app opens, copy the Application Id and save it. You'll use it in a later procedure.

    注意

    この ID は、Office ホスト アプリケーション (たとえば、PowerPoint、Word、Excel) などの別のアプリケーションが、このアプリケーションへの承認されたアクセスを求めるときの「対象ユーザー」値になります。また、そのアプリケーションが Microsoft Graph への承認されたアクセスを求めるときには、このアプリケーションの「クライアント ID」になります。This ID is the “audience” value when other applications, such as the Office host application (e.g., PowerPoint, Word, Excel), seek authorized access to the application. It is also the “client ID” of the application when it, in turn, seeks authorized access to Microsoft Graph.

  6. [アプリケーション シークレット] セクションで、[新しいパスワードを生成する] をクリックします。新しいパスワード (「アプリケーション シークレット」とも呼びます) が示されたポップアップ ダイアログが開きます。このパスワードをすぐにコピーして、アプリケーション ID と共に保存します。 これは、この後の手順で必要になります。その後で、ダイアログを閉じます。In the Application Secrets section, press Generate New Password. A popup dialog opens with a new password (also called an “app secret”) displayed. Copy the password immediately and save it with the application ID. You'll need it in a later procedure. Then close the dialog.

  7. [プラットフォーム] セクションで、[プラットフォームの追加] をクリックします。In the Platforms section, click Add Platform.

  8. 開いたダイアログで、[Web API] を選択します。In the dialog that opens, select Web API.

  9. アプリケーション ID URI は、"api://$App ID GUID$"のフォームで生成されています。An Application ID URI has been generated of the form “api://$App ID GUID$”. [$FQDN-WITHOUT-PROTOCOL$] を二重のスラッシュと GUID の間に(スラッシュ「/」を末尾に追加するかたちで)挿入します。Insert the $FQDN-WITHOUT-PROTOCOL$ (with a forward slash "/" appended to the end) between the double forward slashes and the GUID. ID 全体には api://$FQDN-WITHOUT-PROTOCOL$/$App ID GUID$ というフォームが必要です。例えば、 api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7のようにします。The entire ID should have the form api://$FQDN-WITHOUT-PROTOCOL$/$App ID GUID$; for example api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7.

    注意

    ドメインを既に所有している場合に、所有しているというエラーが表示された場合は、 [クイックスタート」に従います。これは、Azure Active Directory にカスタムドメイン名を追加 し、 それを登録してから、この手順を繰り返します。If you get an error saying that the domain is already owned, but you own it, follow the procedure at Quickstart: Add a custom domain name to Azure Active Directory to register it, and then repeat this step. (Office 365 テナントに管理者の資格情報でサインインしていない場合、このエラーも発生する可能性があります。(This error can also occur if you are not signed in with credentials of an admin in the Office 365 tenancy. 手順 2 を参照してください。See step 2. サインアウトして管理者の資格情報でもう一度サインインし、手順 3 から手順を繰り返します。)Sign out and sign in again with admin credentials and repeat the process from step 3.)

    注意

    ** アプリケーション ID URI** のすぐ下の** スコープ ** 名のドメイン部分は、/access_as_user を末尾に追加するかたちで、一致するように自動的に変更されます。例えば、 api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_userのようになります。The domain part of the Scope name just below the Application ID URI will automatically change to match.

  10. [事前承認済みアプリケーション] セクションで、アドインの Web アプリケーションに対して承認するアプリケーションを特定します。In the Pre-authorized applications section, you identify the applications that you want to authorize to your add-in's web application. 次のそれぞれの ID を事前承認する必要があります。Each of the following IDs needs to be pre-authorized. 1 つの ID を入力するたびに、新しい空のテキスト ボックスが表示されます。Each time you enter one, a new empty textbox appears. (GUID のみを入力してください。)(Enter only the GUID.)

    • d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office)d3590ed6-52b3-4102-aeff-aad2292ab01c (Microsoft Office)
    • 57fb890c-0dab-4253-a5e0-7188c88b2bb4 (Office Online)57fb890c-0dab-4253-a5e0-7188c88b2bb4 (Office Online)
    • bc59ab01-8403-45c6-8796-ac3ef710b3e3 (Office Online)bc59ab01-8403-45c6-8796-ac3ef710b3e3 (Office Online)
  11. それぞれの** [アプリケーション ID]** の横の** [スコープ]** ドロップダウンを開いて、api://$FQDN-WITHOUT-PROTOCOL$/$App ID GUID$/access_as_user のボックスをオンにします。Open the Scope drop-down beside each Application ID and check the box for api://$FQDN-WITHOUT-PROTOCOL$/$App ID GUID$/access_as_user.

  12. [プラットフォーム] セクションの上部にある [プラットフォームの追加] を再度クリックして、[Web] を選択します。Near the top of the Platforms section, click Add Platform again and select Web.

  13. ** [プラットフォーム]** の下側の新しい ** [Web]** セクションで、[リダイレクト URL] として https://$FQDN-WITHOUT-PROTOCOL$ を入力します。In the new Web section under Platforms, enter the following as a Redirect URL: https://$FQDN-WITHOUT-PROTOCOL$.

  14. [Microsoft Graph のアクセス許可] セクションを下にスクロールして、[委任されたアクセス許可] サブセクションを表示します。[追加] ボタンを使用して、[アクセス許可の選択] ダイアログを開きます。Scroll down to the Microsoft Graph Permissions section, the Delegated Permissions subsection. Use the Add button to open a Select Permissions dialog.

  15. ダイアログ ボックスで、 [profile] ボックスおよびアドインに必要な他の AAD および Microsoft Graph 許可をチェックします。In the dialog box, check the boxes for profile and any other AAD and Microsoft Graph permissions that your add-in needs. 次に、例を示します。The following are examples:

    • Files.Read.AllFiles.Read.All
    • offline_accessoffline_access
    • openidopenid
    • profileprofile

      注意

      User.Read アクセス許可は既定でリストされています。The User.Read permission may already be listed by default. 必要でないアクセス許可は依頼しない方がよいため、アドインで実際に必要でなければ、このアクセス許可のチェックボックスをオフにすることをお勧めします。It is a good practice not to ask for permissions that are not needed, so we recommend that you uncheck the box for this permission.

  16. ダイアログの下部にある [OK] をクリックします。At the bottom of the dialog, click OK.

  17. 登録ページの下部にある [保存] をクリックします。At the bottom of the registration page, click Save.

注意

この手順が必要とされるのは、アドインを開発しているときだけです。実際に運用するアドインを AppSource またはアドイン カタログに展開した場合、インストール時に、各ユーザーが個別にそのアドインを信頼するか、管理者が組織のために同意することになります。This procedure is only needed when you're developing the add-in. When your production add-in is deployed to AppSource or an add-in catalog, users will individually trust it or an admin will consent for organization at installation.

この手順は、アドインを登録したに実行してください。Carry out this procedure after you have registered the add-in.

  1. 次に示す文字列内で、プレースホルダー "{application_ID}" を、アドインの登録時にコピーしたアプリケーション ID に置き換えます。 https://login.microsoftonline.com/common/adminconsent?client_id={application_ID}&state=12345In the following string, replace the placeholder “{application_ID}” with the Application ID that you copied when you registered your add-in: https://login.microsoftonline.com/common/adminconsent?client_id={application_ID}&state=12345

  2. そうしてできた URL をブラウザーのアドレス バーに貼り付けて、そこに移動します。Paste the resulting URL into a browser address bar and navigate to it.

  3. ダイアログが表示されたら、管理者の資格情報を使用して Office 365 テナントにサインインします。When prompted, sign in with the admin credentials to your Office 365 tenancy.

  4. その後、Microsoft Graph データにアクセスするためのアクセス許可をアドインに付与するように求めるダイアログが表示されます。[承諾] をクリックします。You are then prompted to grant permission for your add-in to access your Microsoft Graph data. Click Accept.

  5. ブラウザのウィンドウ (タブ) は、アドインの登録時に指定した リダイレクトURL にリダイレクトされます。The browser window/tab is then redirected to the Redirect URL that you specified when you registered the add-in, so the home page of the add-in opens in the browser. アドインの Web アプリケーションを実行している場合は、アドインのホームページがブラウザで開きます。それ以外の場合は、404 エラーが発生します。If the add-in's web application is running, the home page of the add-in opens in the browser; otherwise, you'll get a 404 error. しかし、ブラウザがホームページを開こうとしたという事実は、同意がうまく与えられたことを意味します。But the fact that the browser attempted to open the home page means that consent was successfully granted.

注意

開発者向け O365 テナントを使用している場合は、この手順をベスト プラクティスとしてお勧めします。We recommend this procedure as a best practice if you are using a Developer O365 tenant. ただし、お好みに応じて、開発中の SSO アドインをサイドローディングして、ユーザーに同意書を要求することもできます。However, if you prefer, it is possible to sideload an SSO add-in under development and prompt the user with a consent form. 詳細については、 Windows のサイドローディング および Office Online のサイドローディング を参照してください。For more information, see Sideload on Windows and Sideload on Office Online.

アドインを構成するConfigure the add-in

  1. 次の文字列内のプレースホルダー "{tenant_ID}" を Office 365 テナントIDに置き換えます。In the following string, replace the placeholder “{tenant_ID}” with your Office 365 tenant ID. Office 365テナントIDを見つける 」にあるいずれかの方法を使用して、IDを取得します。Use one of the methods in Find your Office 365 tenant ID to obtain it.

    https://login.microsoftonline.com/{tenant_ID}/v2.0

  2. Visual Studio で、web.config を開きます。[appSettings] セクションには、値を割り当てる必要のあるいくつかのキーがあります。In Visual Studio, open the web.config. There are some keys in the appSettings section to which you need to assign values.

  3. "ida:Issuer" という名前のキーの値として、手順 1 で作成した文字列を使用します。この値に、空白スペースが含まれていないことを確認してください。Use the string you constructed in step 1 as the value to the key named “ida:Issuer”. Be sure there are no blank spaces in the value.

  4. 次に示す値を対応するキーに代入します。Assign the following values to the corresponding keys:

    キーKey Value
    ida:ClientIDida:ClientID アドインの登録時に取得したアプリケーション ID。The application ID you obtained when you registered the add-in.
    ida:Audienceida:Audience アドインの登録時に取得したアプリケーション ID。The application ID you obtained when you registered the add-in.
    ida:Passwordida:Password アドインの登録時に取得したパスワード。TThe password you obtained when you registered the add-in.

    次に、4 つのキーの変更後の例を示します。ClientID と Audience が同じになっている点に注目してください。両方の目的に単一のキーを使用することもできますが、これらは必ずしも同じではないため、別々に保持しておくと web.config のマークアップが再利用しやすくなります。また、別のキーを使用することで、アドインが Office ホストに関連する OAuth リソースと、Microsoft Graph に関連する OAuth クライアントの両方でであるという考えが補強されます。The following is an example of what the four keys you changed should look like. Note that ClientID and Audience are the same. You can also use a single key for both purposes, but your web.config markup is more reusable if you keep them separate because they aren't always the same. Also, having separate keys reinforces the idea that your add-in is both an OAuth resource, relative to the Office host, and an OAuth client, relative to Microsoft Graph.

    <add key=”ida:ClientID" value="12345678-1234-1234-1234-123456789012" />
    <add key="ida:Audience" value="12345678-1234-1234-1234-123456789012" />
    <add key="ida:Password" value="rFfv17ezsoGw5XUc0CDBHiU" />
    <add key="ida:Issuer" value="https://login.microsoftonline.com/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/v2.0" />
    

    注意

    その他の [appSettings] セクションの設定は、未変更のままにします。Leave the other settings in the appSettings section unchanged.

  5. ファイルを保存して閉じます。Save and close the file.

  6. アドイン プロジェクトで、アドイン マニフェスト ファイル "Office-Add-in-ASPNET-SSO.xml" を開きます。In the add-in project, open the add-in manifest file “Office-Add-in-ASPNET-SSO.xml”.

  7. ファイルの最後までスクロールします。Scroll to the bottom of the file.

  8. 終了タグの直前に、以下のマークアップがあります。</VersionOverrides>Just above the end </VersionOverrides> tag, you'll find the following markup:

    <WebApplicationInfo>
      <Id>{application_GUID here}</Id>
      <Resource>api://localhost:44355/{application_GUID here}</Resource>
      <Scopes>
          <Scope>Files.Read.All</Scope>
          <Scope>offline_access</Scope>
          <Scope>openid</Scope>
          <Scope>profile</Scope>
      </Scopes>
    </WebApplicationInfo>
    
  9. このマークアップ内の両方の場所のプレースホルダー “{application_GUID here}” を、アドインの登録時にコピーしたアプリケーション ID に置き換えます。Replace the placeholder “{application_GUID here}” in both places in the markup with the Application ID that you copied when you registered your add-in. 「{} 」は ID の一部ではないので、これらを含めないでください。The "{}" are not part of the ID, so do not include them. これは、web.config の ClientID と Audience に使用したものと同じ ID です。This is the same ID you used in for the ClientID and Audience in the web.config.

    注意

    • [リソース] の値は、アドインの登録に Web API プラットフォームを追加したときに設定した [アプリケーション ID URI] です。The Resource value is the Application ID URI you set when you added the Web API platform to the registration of the add-in.
    • [範囲] セクションは、アドインが AppSource から販売された場合に、同意ダイアログ ボックスを生成するためにのみ使用します。The Scopes section is used only to generate a consent dialog box if the add-in is sold through AppSource.
  10. Visual Studio で、[エラー一覧][警告] タブを開きます。Open the Warnings tab of the Error List in Visual Studio. <WebApplicationInfo><VersionOverrides> の有効な子ではないという警告が表示される場合は、Visual Studio 2017 プレビューのバージョンで SSO マークアップが認識されていません。If there is a warning that <WebApplicationInfo> is not a valid child of <VersionOverrides>, your version of Visual Studio 2017 Preview does not recognize the SSO markup. 回避策として、Word、Excel、または PowerPoint のアドインに対して、次の操作を行います。As a workaround, do the following for a Word, Excel, or PowerPoint add-in. (Outlook アドインを使用している場合は、以下の回避策を参照してください。)(If you are working with an Outlook add-in see the workaround below.)

    • Word、Excel、および PowerPoint の回避策Workaround for Word, Excel, and Powerpoint

      1. マニフェストの </VersionOverrides> の終了タグの直前の <WebApplicationInfo> セクションをコメント アウトします。Comment out the <WebApplicationInfo> section from the manifest just above the end of </VersionOverrides>.

      2. F5 キーを押してデバッグ セッションを開始します。これにより、次のフォルダーにマニフェストのコピーが作成されます (これには、Visual Studio よりもファイル エクスプローラーの方が容易にアクセスできます): Office-Add-in-ASP.NET-SSO\Complete\Office-Add-in-ASPNET-SSO\bin\Debug\OfficeAppManifestsPress F5 to start a debugging session. This will create a copy of the manifest in the following folder (which is easier to access in File Explorer than in Visual Studio): Office-Add-in-ASP.NET-SSO\Complete\Office-Add-in-ASPNET-SSO\bin\Debug\OfficeAppManifests

      3. マニフェストのコピーから、<WebApplicationInfo> セクションの周囲のコメント構文を削除します。In the copy of the manifest, remove the comment syntax around the <WebApplicationInfo> section.

      4. マニフェストのコピーを保存します。Save the copy of the manifest.

      5. この時点で、次回 F5 キーを押したときに、このマニフェストのコピーが Visual Studio によって上書きされないようにする必要があります。ソリューション エクスプローラーの上部にあるソリューション ノード (どちらのプロジェクト ノードでもない) を右クリックします。Now you must prevent Visual Studio from overwriting the copy of the manifest the next time you press F5. Right-click the solution node at the very top of Solution Explorer (not either of the project nodes).

      6. コンテキスト メニューから [プロパティ] を選択します。[ソリューション プロパティ ページ] ダイアログ ボックスが開きます。Select Properties from the context menu and a Solution Property Pages dialog box opens.

      7. [構成プロパティ] を展開し、[構成] を選択します。Expand Configuration Properties and select Configuration.

      8. Office-Add-in-ASPNET-SSO プロジェクト (Office-Add-in-ASPNET-SSO-WebAPI プロジェクトではありません) の行で、[ビルド][展開] を選択解除します。Deselect Build and Deploy in the row for the Office-Add-in-ASPNET-SSO project (not the Office-Add-in-ASPNET-SSO-WebAPI project).

      9. [OK] をクリックしてダイアログ ボックスを閉じます。Press OK to close the dialog box.

    • Outlook の回避策Workaround for Outlook

      1. 開発用コンピューターで、既存の MailAppVersionOverridesV1_1.xsd を探します。On your development machine, locate the existing MailAppVersionOverridesV1_1.xsd. の下の Visual Studio インストール ディレクトリに配置されています。./Xml/Schemas/{lcid}This should be located in your Visual Studio installation directory under ./Xml/Schemas/{lcid}. たとえば、英語版 (米国) の VS 2017 32 ビットの標準インストールの場合、完全なパスは、C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Xml\Schemas\1033 になります。For example, on a typical installation of VS 2017 32-bit on an English (US) system, the full path would be C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Xml\Schemas\1033.

      2. 既存のファイルの名前を、MailAppVersionOverridesV1_1.old に変更します。Rename the existing file to MailAppVersionOverridesV1_1.old.

      3. 変更したこのファイルを、フォルダーにコピーします。変更済みの MailAppVersionOverrides スキーマCopy this modified version of the file into the folder: Modified MailAppVersionOverrides Schema

  11. Visual Studio でメインのマニフェスト ファイルを保存して閉じます。Save and close the main manifest file in Visual Studio.

クライアント側のコードの作成Code the client side

  1. [Scripts] フォルダー内の Home.js ファイルを開きます。これには、一部のコードが既に含まれています。Open the Home.js file in the Scripts folder. It already has some code in it:

    • メソッドへの割り当てが、getGraphAccessTokenButton ボタン クリック イベントへのハンドラーの割り当てになります。Office.initializeAn assignment to the Office.initialize method that, in turn, assigns a handler to the getGraphAccessTokenButton button click event.
    • メソッドは、作業ウィンドウの下側に Microsoft Graph から返されたデータ (またはエラー メッセージ) を表示するものです。showResultA showResult method that will display data returned from Microsoft Graph (or an error message) at the bottom of the task pane.
    • メソッドは、エンド ユーザーを対象としていないエラーをコンソールにログ出力するものです。logErrorsA logErrors method that will log to console errors that are not intended for the end user.
  2. Office.initialize への割り当ての下に、次に示すコードを追加します。このコードについては、次の点に注意してください。Below the assignment to Office.initialize, add the code below. Note the following about this code:

    • アドインのエラー処理により、アクセス トークンの取得が別のオプションのセットを使用して自動的に再試行されることがあります。The error-handling in the add-in will sometimes automatically attempt a second time to get an access token, using a different set of options. カウンター変数 timesGetOneDriveFilesHasRun とフラグ変数 triedWithoutForceConsent を使用して、失敗するトークン取得の繰り返しからユーザーが抜け出せるようにします。The counter variable timesGetOneDriveFilesHasRun, and the flag variable triedWithoutForceConsent are used to ensure that the user isn't cycled repeatedly through failed attempts to get a token.
    • この後の手順では getDataWithToken メソッドを作成しますが、そのメソッドで forceConsent というオプションが false に設定される点に注意してください。詳細については、次の手順で説明します。You create the getDataWithToken method in the next step, but note that it sets an option called forceConsent to false. More about that in the next step.

      var timesGetOneDriveFilesHasRun = 0;
      var triedWithoutForceConsent = false;
      
      function getOneDriveFiles() {
        timesGetOneDriveFilesHasRun++;
        triedWithoutForceConsent = true;
        getDataWithToken({ forceConsent: false });
      }   
      
  3. メソッドの下に、次のコードを追加します。このコードについては、次の点に注意してください。getOneDriveFilesBelow the getOneDriveFiles method, add the code below. Note the following about this code:

    • getAccessTokenAsync は Office.js の新しい API です。これにより、アドインは Office ホスト アプリケーション (Excel、PowerPoint、Word など) に、アドインへのアクセス トークン (Office にサインインしているユーザーのトークン) を要求できるようになります。The is the new API in Office.js that enables an add-in to ask the Office host application (Excel, PowerPoint, Word, etc.) for an access token to the add-in (for the user signed into Office). その Office ホスト アプリケーションが、Azure AD 2.0 エンドポイントにこのトークンを要求します。The Office host application, in turn, asks the Azure AD 2.0 endpoint for the token. アドインの登録時に、アドインに対する Office ホストを事前認証しているため、Azure AD はそのトークンを送信します。Since you preauthorized the Office host to your add-in when you registered it, Azure AD will send the token.
    • Office にサインインしているユーザーがいない場合、Office ホストはユーザーにサインインを求めるダイアログを表示します。If no user is signed into Office, the Office host will prompt the user to sign in.
    • オプションのパラメーター forceConsentfalse に設定すると、ユーザーがアドインを使用するたびに、Office ホストにアドインへのアクセス権を付与するための同意を求めるダイアログが表示されなくなります。The options parameter sets forceConsent to false, so the user will not be prompted to consent to giving the Office host access to your add-in every time she or he uses the add-in. ユーザーが初めてアドインを実行すると、getAccessTokenAsync の呼び出しは失敗しますが、この後の手順で追加するエラー処理ロジックにより、forceConsent オプションを true に設定した再呼び出しが自動的に実行され、ユーザーに同意を求めるダイアログが表示されます。ただし、これは初回時のみ実行されます。The first time the user runs the add-in, the call of getAccessTokenAsync will fail, but error-handling logic that you add in a later step will automatically re-call with the forceConsent option set to true and the user will be prompted to consent, but only that first time.
    • メソッドは、この後の手順で作成します。handleClientSideErrorsYou will create the handleClientSideErrors method in a later step.

      function getDataWithToken(options) {
      Office.context.auth.getAccessTokenAsync(options,
        function (result) {
            if (result.status === "succeeded") {
                TODO1: Use the access token to get Microsoft Graph data.
            }
            else {
                handleClientSideErrors(result);
            }
        });
      }
      
  4. TODO1 を次に示す行に置き換えます。getData メソッドとサーバー側の "/api/values" ルートは、この後の手順で作成します。エンドポイントには、相対 URL を使用します。これは、その URL がアドインと同じドメインでホストされている必要があるためです。Replace the TODO1 with the following lines. You create the getData method and the server-side “/api/values” route in later steps. A relative URL is used for the endpoint because it must be hosted on the same domain as your add-in.

    accessToken = result.value;
    getData("/api/values", accessToken);
    
  5. メソッドの下に、以下を追加します。このコードについては、次の点に注意してください。getOneDriveFilesBelow the getOneDriveFiles method, add the following. About this code, note:

    • このメソッドは、特定の Web API エンドポイントを呼び出して、Office ホスト アプリケーションがアドインへのアクセスに使用したものと同じアクセス トークンを渡します。サーバー側では、このアクセス トークンが Microsoft Graph へのアクセス トークンを取得するための「代理 (on-behalf-of)」フローで使用されます。This method calls a specified Web API endpoint and passes it the same access token that the Office host application used to get access to your add-in. On the server-side, this access token will be used in the “on behalf of” flow to obtain an access token to Microsoft Graph.
    • メソッドは、この後の手順で作成します。handleServerSideErrorsYou will create the handleServerSideErrors method in a later step.

      function getData(relativeUrl, accessToken) {
        $.ajax({
            url: relativeUrl,
            headers: { "Authorization": "Bearer " + accessToken },
            type: "GET"
        })
        .done(function (result) {
            showResult(result);
        })
        .fail(function (result) {
            handleServerSideErrors(result);
        }); 
      }
      

エラー処理のメソッドを作成するCreate the error-handling methods

  1. メソッドの下に、次のメソッドを追加します。getDataBelow the getData method, add the following method. このメソッドは、Office ホストがアドインの Web サービスへのアクセス トークンを取得できないときに、アドインのクライアントでエラーを処理します。This method will handle errors in the add-in's client when the Office host is unable to obtain an access token to the add-in's web service. こうしたエラーはエラー コードで報告されるため、このメソッドでは switch ステートメントを使用してエラーを識別します。These errors are reported with an error code, so the method uses a switch statement to distinguish them.

    function handleClientSideErrors(result) {
    
        switch (result.error.code) {
    
            // TODO2: Handle the case where user is not logged in, or the user cancelled, without responding, a
            //        prompt to provide a 2nd authentication factor. 
    
            // TODO3: Handle the case where the user's sign-in or consent was aborted.
    
            // TODO4: Handle the case where the user is logged in with an account that is neither work or school, 
            //        nor Micrososoft Account.
    
            // TODO5: Handle an unspecified error from the Office host.
    
            // TODO6: Handle the case where the Office host cannot get an access token to the add-ins 
            //        web service/application.
    
            // TODO7: Handle the case where the user tiggered an operation that calls `getAccessTokenAsync` 
            //        before a previous call of it completed.
    
            // TODO8: Handle the case where the add-in does not support forcing consent.
    
            // TODO9: Log all other client errors.
        }
    }
    
  2. を次のコードに置き換えます。TODO2Replace TODO2 with the following code. エラー 13001 は、ユーザーがログインしていない場合、または 2 番目の認証要素の指定を求めるダイアログに応答しないでキャンセルした場合に発生します。Error 13001 occurs when the user is not logged in, or the user cancelled, without responding, a prompt to provide a 2nd authentication factor. どちらの場合も、このコードでは getDataWithToken メソッドを再実行して、サインインを求めるダイアログの表示を強制するようにオプションを設定します。In either case, the code re-runs the getDataWithToken method and sets an option to force a sign-in prompt.

    case 13001:
        getDataWithToken({ forceAddAccount: true });
        break;
    
  3. を次のコードに置き換えます。TODO3Replace TODO3 with the following code. エラー 13002 は、ユーザーのサインインまたは同意が中断された場合に発生します。Error 13002 occurs when user's sign-in or consent was aborted. ユーザーに対して 1 回だけ再試行を求めます。Ask the user to try again but no more than once again.

    case 13002:
        if (timesGetOneDriveFilesHasRun < 2) {
            showResult(['Your sign-in or consent was aborted before completion. Please try that operation again.']);
        } else {
            logError(result);
        }          
        break; 
    
  4. TODO4\を次のコードに置き換えます。Replace TODO4 with the following code. エラー 13003 は、ユーザーが職場または学校アカウントと、Micrososoft アカウントのどちらでもないアカウントでログインしている場合に発生します。Error 13003 occurs when user is logged in with an account that is neither work or school, nor Micrososoft Account. ユーザーに対して、サインアウトしてからサポートされているアカウントの種類で再度サインインするように求めます。Ask the user to sign-out and then in again with a supported account type.

    case 13003: 
        showResult(['Please sign out of Office and sign in again with a work or school account, or Microsoft account. Other kinds of accounts, like corporate domain accounts do not work.']);
        break;   
    

    注意

    エラー 13004 と 13005 は、開発時にのみ発生するため、このメソッドでは処理しません。Errors 13004 and 13005 are not handled in this method because they should only occur in development. これらは、ランタイム コードで修正できるものではなく、エンド ユーザーに報告しても意味がありません。They cannot be fixed by runtime code and there would be no point in reporting them to an end user.

  5. を次のコードと置き換えます。エラー 13006 は、Office ホストで未指定のエラーがある場合に発生します。ホストが不安定な状態にあることを示している可能性があります。ユーザーに Office の再起動を求めます。TODO5Replace TODO5 with the following code. Error 13006 occurs when there has been an unspecified error in the Office host that may indicate that the host is in an unstable state. Ask the user to restart Office.

    case 13006:
        showResult(['Please save your work, sign out of Office, close all Office applications, and restart this Office application.']);
        break;        
    
  6. を次のコードに置き換えます。TODO6Replace TODO6 with the following code. エラー 13007 は、Office ホストの AAD との相互作用に問題があり、ホストがアドイン Web サービス/アプリケーションへのアクセス トークンを取得できない場合に発生します。Error 13007 occurs when something has gone wrong with the Office host's interaction with AAD so the host cannot get an access token to the add-ins web service/application. ネットワークに一時的な問題が発生している可能性があります。This may be a temporary network issue. しばらく待ってから再試行するようにユーザーに求めます。Ask the user to try again later.

    case 13007:
        showResult(['That operation cannot be done at this time. Please try again later.']);
        break;      
    
  7. TODO7 を次のコードに置き換えます。エラー 13008 は、前回の getAccessTokenAsync 呼び出しが完了する前に、それを呼び出す操作をユーザーがトリガーしたときに発生します。Replace TODO7 with the following code. Error 13008 occurs when the user tiggered an operation that calls getAccessTokenAsync before a previous call of it completed.

    case 13008:
        showResult(['Please try that operation again after the current operation has finished.']);
        break;
    
  8. を次のコードに置き換えます。TODO8Replace TODO8 with the following code. エラー 13009 は、アドインが強制的な同意をサポートしていないときに、forceConsent オプションを true に設定して getAccessTokenAsync を呼び出した場合に発生します。Error 13009 occurs when the add-in does not support forcing consent, but getAccessTokenAsync was called with the forceConsent option set to true. 通常、この場合は、コードによって同意オプションを false に設定して自動的に getAccessTokenAsync を再実行する必要があります。In the usual case when this happens the code should automatically re-run getAccessTokenAsync with the consent option set to false. ただし、forceConsenttrue に設定してメソッドを呼び出すこと自体が、そのオプションを false に設定したメソッドの呼び出しで発生したエラーに対する自動的な応答の場合もあります。However, in some cases, calling the method with forceConsent set to true was itself an automatic response to an error in a call to the method with the option set to false. その場合は、コードで再試行するのではなく、ユーザーにサインアウトしてから再度サインインするように通知する必要があります。In that case, the code should not try again, but instead it should advise the user to sign out and sign in again.

    case 13009:
        if (triedWithoutForceConsent) {
            showResult(['Please sign out of Office and sign in again with a work or school account, or Microsoft account.']);
        } else {
            getDataWithToken({ forceConsent: false });
        }
        break;
    
  9. を次のコードに置き換えます。TODO9Replace TODO9 with the following code.

    default:
        logError(result);
        break;
    
  10. メソッドの下に、次のメソッドを追加します。このメソッドは、代理 (on-behalf-of) フローの実行時または Microsoft Graph からのデータの取得時の問題により、アドインの Web サービスで発生したエラーを処理します。handleClientSideErrorsBelow the handleClientSideErrors method, add the following method. This method will handle errors in the add-in's web service when something goes wrong in executing the on-behalf-of flow or in getting data from Microsoft Graph.

    function handleServerSideErrors(result) {
    
        // TODO10: Parse the JSON response.
    
        // TODO11: Handle the case where AAD asks for an additional form of authentication.
    
        // TODO12: Handle missing consent and scope (permission) related issues.
    
        // TODO13: Handle the case where the token sent to Microsoft Graph in the request for 
        //         data is expired or invalid.
    
        // TODO14: Log all other server errors.
    }
    
  11. を次のコードに置き換えます。TODO10Replace TODO10 with the following code. アドインの Web サービスがアドインのクライアント側に渡すほとんどの 4xx エラーには、その応答内に ExceptionMessage プロパティが含まれています。このプロパティには、AADSTS (Azure Active Directory Secure Token Service) エラー番号などのデータが格納されています。Note that for most of the 4xx errors that the add-in's web service will pass to the add-in's client-side, there will be an ExceptionMessage property in the response that contains the AADSTS (Azure Active Directory Secure Token Service) error number as well as other data. ただし、AAD がアドインの Web サービスに追加の認証要素を求めるメッセージを送信するときには、そのメッセージに特殊な Claims プロパティが含まれます。このプロパティによって、どの追加要素が必要になるかが (コード番号で) 示されます。However, when AAD sends a message to the add-in's web service asking for an additonal authentication factor, the message contains a special Claims property that specifies (with a code number) what additional factor is needed. HTTP 応答を作成してクライアントに送信する ASP.NET API は、この Claims プロパティを認識しないため、このプロパティを応答オブジェクトに含めません。The ASP.NET APIs that create and send HTTP Responses to clients do not know about this Claims property, so they do not include it in the Response object. この後の手順で作成するサーバー側のコードでは、これに対処するために、手動で応答オブジェクトに Claims 値を追加しています。Server-side code that you will create in a later step will cope with this by manually adding the Claims value to the Response object. この値は、Message プロパティに含めるため、コードでは、そのプロパティも解析する必要があります。This value will be in the Message property, so the code needs to parse out that property as well.

    var exceptionMessage = JSON.parse(result.responseText).ExceptionMessage;
    var message = JSON.parse(result.responseText).Message;
    
  12. TODO11 を次のコードに置き換えます。このコードの注意点は次のとおりです。Replace TODO11 with the following code. Note about this code:

    • エラー 50076 は、Microsoft Graph が認証の追加フォームを必要とする場合に発生します。Error 50076 occurs when Microsoft Graph requires an additional form of authentication.
    • Office ホストは、authChallenge オプションとして Claims 値を使用して新しいトークンを取得します。The Office host should get a new token with the Claims value as the authChallenge option. これにより、認証のすべての必要なフォームをユーザーに表示するように AAD に指示します。This tells AAD to prompt the user for all required forms of authentication.

      if (message) {
        if (message.indexOf("AADSTS50076") !== -1) {
            var claims = JSON.parse(message).Claims;
            var claimsAsString = JSON.stringify(claims);
            getDataWithToken({ authChallenge: claimsAsString });
        }
      }    
      
  13. TODO12\を次のコードに置き換えます。Replace TODO12 with the following code. このコードの3つの TODO を次のいくつかの手順で 内部 条件ブロックに置き換えます。You will replace the three TODOs in this code with an inner conditional block in the next few steps.

    else if (exceptionMessage) {
    
        // TODO12A: Handle the case where consent has not been granted, or has been revoked.
    
        // TODO12B: Handle the case where an invalid scope (permission) was used in the on-behalf-of flow.
    
        // TODO12C: Handle the case where the token that the add-in's client-side sends to it's 
        //          server-side is not valid because it is missing `access_as_user` scope (permission).
    }
    
  14. TODO12A\を次のコードに置き換えます。Replace TODO12A with the following code. (これは 内部 の条件付きブロックの最初の部分)このコードに関する注意してください。(This creates the first part of an inner conditional block.) Note about this code:

    • エラー 65001 は、1 つ以上のアクセス許可について Microsoft Graph にアクセスするための同意が与えられていない (または取り消されている) ことを意味します。Error 65001 means that consent to access Microsoft Graph was not granted (or was revoked) for one or more permissions.
    • アドインでは、forceConsent オプションを true に設定して新しいトークンを取得する必要があります。The add-in should get a new token with the forceConsent option set to true.

      if (exceptionMessage.indexOf('AADSTS65001') !== -1) {
        showResult(['Please grant consent to this add-in to access your Microsoft Graph data.']);        
        /*
            THE FORCE CONSENT OPTION IS NOT AVAILABLE IN DURING PREVIEW. WHEN SSO FOR
            OFFICE ADD-INS IS RELEASED, REMOVE THE showResult LINE ABOVE AND UNCOMMENT
            THE FOLLOWING LINE.
        */
       // getDataWithToken({ forceConsent: true });
      }    
      
  15. を次のコードに置き換えます。このコードの注意点は次のとおりです。TODO12BReplace TODO12B with the following code. Note about this code:

    • エラー 70011 には複数の意味があります。無効なスコープ (アクセス許可) が要求されていることを意味する場合、このアドインに重要となります。コードでは番号だけでなくエラーの説明全体を確認します。Error 70011 has multiple meanings. The one that matters to this add-in is when it means that an invalid scope (permission) has been requested, so the code checks for the full error description, not just the number.
    • アドインでは、エラーを報告する必要があります。The add-in should report the error.

      else if (exceptionMessage.indexOf("AADSTS70011: The provided value for the input parameter 'scope' is not valid.") !== -1) {
        showResult(['The add-in is asking for a type of permission that is not recognized.']);
      }    
      
  16. を次のコードに置き換えます。このコードの注意点は次のとおりです。TODO12CReplace TODO12C with the following code. Note about this code:

    • この後の手順で作成するサーバー側のコードでは、アドインのクライアントが AAD に送信して代理 (on-behalf-of) フローで使用されるアクセス トークンに access_as_user スコープ (アクセス許可) が含まれていない場合に、メッセージ Missing access_as_user を送信します。Server-side code that you create in a later step will send the message Missing access_as_user if the access_as_user scope (permission) is not in the access token that the add-in's client sends to AAD to be used in the on-behalf-of flow.
    • アドインでは、エラーを報告する必要があります。The add-in should report the error.

      else if (exceptionMessage.indexOf('Missing access_as_user.') !== -1) {
        showResult(['Microsoft Office does not have permission to get Microsoft Graph data on behalf of the current user.']);
      }    
      
  17. TODO13\を次のコードに置き換えます。Replace TODO13 with the following code. (これは、 外側 の条件付きブロックの一部であり、かっこで始まる構造体の直後にする必要があります else if (exceptionMessage) { と同じレベルのインデント設定されます)。このコードに関する注意してください。(This is part of the outer conditional block and should be immediately after the close bracket of the structure that begins with else if (exceptionMessage) { and at the same level of indentation.) Note about this code:

    • サーバー側のコードで使用する ID ライブラリ (Microsoft Authentication Library - MSAL) では、期限切れのトークンや無効なトークンが Microsoft Graph に送信されないようにする必要があります。ただし、その事態が発生した場合は、アドインの Web サービスに Microsoft Graph から返されるエラーにコード InvalidAuthenticationToken が含まれています。後の手順で作成するサーバー側のコードは、このメッセージをアドインのクライアントに中継します。The identity library that you will be using in the server-side code (Microsoft Authentication Library - MSAL) should ensure that no expired or invalid token is sent to Microsoft Graph; but if it does happen, the error that is returned to the add-in's web service from Microsoft Graph has the code InvalidAuthenticationToken. Server-side code you will create in a latter step will relay this message to the add-in's client.
    • この場合、アドインはカウンター変数とフラグ変数をリセットしてから、ボタン ハンドラー メソッドを再呼び出しすることで、認証プロセス全体を最初から開始する必要があります。In this case, the add-in should start the entire authentication process over by resetting the counter and flag varibles, and then re-calling the button handler method.

      // If the token sent to MS Graph is expired or invalid, start the whole process over.
      else if (result.code === 'InvalidAuthenticationToken') {
        timesGetOneDriveFilesHasRun = 0;
        triedWithoutForceConsent = false;
        getOneDriveFiles();
      }    
      
  18. を次のコードに置き換えます。TODO14Replace TODO14 with the following code.

    else {
        logError(result);
    }    
    
  19. ファイルを保存して閉じます。Save and close the file.

サーバー側のコードを作成するCode the server side

OWIN ミドルウェアを構成するConfigure the OWIN middleware

  1. プロジェクトのルートにある Startup.cs を開きます。Open the Startup.cs file in the root of the project.

  2. Startup クラスの宣言にキーワード partial を追加します (まだ追加されていない場合)。これは、次のようになります。Add the keyword partial to the declaration of the Startup class, if it is not already there. It should look like this:

    public partial class Startup

  3. メソッドの本文に、次に示す行を追加します。ConfigureAuth メソッドは、この後の手順で作成します。ConfigurationAdd the following line to the body of the Configuration method. You create the ConfigureAuth method in a later step.

    ConfigureAuth(app);

  4. ファイルを保存して閉じます。Save and close the file.

  5. App_Start フォルダーを右クリックして、[追加] > [クラス] を選択します。Right-click the App_Start folder and select Add > Class.

  6. [新しい項目の追加] ダイアログで、ファイルに「Startup.Auth.cs」という名前を付けて [追加] をクリックします。In the Add new item dialog name the file Startup.Auth.cs and then click Add.

  7. 新しいファイルで名前空間の名前を Office_Add_in_ASPNET_SSO_WebAPI に短縮します。Shorten the namespace name in the new file to Office_Add_in_ASPNET_SSO_WebAPI.

  8. ファイルの先頭に、次に示す using ステートメントがすべて揃っていることを確認します。Ensure that all of the following using statements are at the top of the file.

    using Owin;
    using System.IdentityModel.Tokens;
    using System.Configuration;
    using Microsoft.Owin.Security.OAuth;
    using Microsoft.Owin.Security.Jwt;
    using Office_Add_in_ASPNET_SSO_WebAPI.App_Start;
    
  9. クラスの宣言にキーワード partial を追加します (まだ追加されていない場合)。これは、次のようになります。StartupAdd the keyword partial to the declaration of the Startup class, if it is not already there. It should look like this:

    public partial class Startup

  10. 次に示すメソッドを Startup クラスに追加します。このメソッドでは、クライアント側の Home.js ファイルの getData メソッドから渡されたアクセス トークンを OWIN ミドルウェアで検証する方法を指定します。承認プロセスは、[Authorize] 属性で修飾された Web API エンドポイントが呼び出されたときには必ずトリガーされます。Add the following method to the Startup class. This method specifies how the OWIN middleware will validate the access tokens that are passed to it from the getData method in the client-side Home.js file. The authorization process is triggered whenever a Web API endpoint that is decorated with the [Authorize] attribute is called.

    public void ConfigureAuth(IAppBuilder app)
    {
        // TODO3: Configure the validation settings
        // TODO4: Specify the type of authorization and the discovery endpoint
        // of the secure token service.
    }
    
  11. TODO3 を次のように置き換えます。Replace the TODO3 with the following. このコードの注意点は次のとおりです。Note about this code:

    • このコードでは、Office ホストから得られるアクセス トークン (getData のクライアント側呼び出しによって渡されるトークン) で指定された対象ユーザーとトークン発行者が web.config で指定された値と一致する必要があることを OWIN に指示します。The code instructs OWIN to ensure that the audience and token issuer specified in the access token that comes from the Office host (and is passed on by the client-side call of getData) must match the values specified in the web.config.
    • true に設定することで、OWIN は Office ホストからの Raw トークンを保存するようになります。これは、アドインが「代理」フローで Microsoft Graph へのアクセス トークンを取得するために必要になります。SaveSigninTokenSetting SaveSigninToken to true causes OWIN to save the raw token from the Office host. The add-in needs it to obtain an access token to Microsoft Graph with the “on behalf of” flow.
    • OWIN ミドルウェアでは、スコープは検証されません。access_as_user が含まれている必要があるアクセス トークンのスコープは、コントローラーで検証されます。Scopes are not validated by the OWIN middleware. The scopes of the access token, which should include access_as_user, is validated in the controller.

      var tvps = new TokenValidationParameters
        {
            ValidAudience = ConfigurationManager.AppSettings["ida:Audience"],
            ValidIssuer = ConfigurationManager.AppSettings["ida:Issuer"],
            SaveSigninToken = true
        };
      
  12. TODO4 を次のように置き換えます。このコードの注意点は次のとおりです。Replace TODO4 with the following. Note about this code:

    • より一般的な UseWindowsAzureActiveDirectoryBearerAuthentication は Azure AD V2 エンドポイントに準拠していないため、その代わりとしてメソッド UseOAuthBearerAuthentication が呼び出されます。The method UseOAuthBearerAuthentication is called instead of the more common UseWindowsAzureActiveDirectoryBearerAuthentication because the latter is not compatible with the Azure AD V2 endpoint.
    • このメソッドに渡される探索 URL は、Office ホストから受け取ったアクセス トークンの署名の検証に必要になるキーを取得するための方法を OWIN ミドルウェアが取得する場所になります。The discovery URL that is passed to the method is where the OWIN middleware obtains instructions for getting the key it needs to verify the signature on the access token received from the Office host.

      app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
        {
            AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"))
        });
      
  13. ファイルを保存して閉じます。Save and close the file.

/api/values コントローラーを作成するCreate the /api/values controller

  1. ファイル Controllers\ValueController.cs を開きます。Open the file Controllers\ValueController.cs.

  2. ファイルの先頭に、次に示す using ステートメントがあることを確認します。Ensure that the following using statements are at the top of the file.

    using Microsoft.Identity.Client;
    using System.IdentityModel.Tokens;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using System.Web.Http;
    using System;
    using System.Net;
    using System.Net.Http;
    using Office_Add_in_ASPNET_SSO_WebAPI.Helpers;
    using Office_Add_in_ASPNET_SSO_WebAPI.Models;
    
  3. を宣言している行のすぐ上に、属性 [Authorize] を追加します。これにより、アドインはコントローラー メソッドが呼び出されたときに、最後の手順で構成した承認プロセスを必ず実行するようになります。アドインへの有効なアクセス トークンを持つ呼び出し元のみが、コントローラーのメソッドを起動できます。ValuesControllerJust above the line that declares the ValuesController, add the [Authorize] attribute. This ensures that your add-in will run the authorization process that you configured in the last procedure whenever a controller method is called. Only callers with a valid access token to your add-in can invoke the methods of the controller.

    注意

    運用環境の ASP.NET MVC Web API サービスには、1 つ以上のカスタム FilterAttribute クラスに代理 (on-behalf-of) フロー用のカスタム ロジックを用意する必要があります。A production ASP.NET MVC Web API service should have custom logic for the on-behalf-of flow in one or more custom FilterAttribute classes. この学習用サンプルでは、メイン コントローラーにロジックを配置して、認証とデータのフェッチ ロジックの全体的なフローを簡単に把握できるようにしています。This educational sample puts the logic in the main controller so that the entire flow of the authorization and data fetching logic can be easily followed. さらに、このサンプルが「Azure Samples」の承認サンプルのパターンと一致するようになります。This also makes the sample consistent with the pattern of authorization samples in Azure Samples.

  4. 次のメソッドを ValuesController に追加します。Add the following method to the ValuesController. 戻り値は、Task<IEnumerable<string>> ではなく GET api/values メソッドでより一般的な Task<HttpResponseMessage> になる点に注意してください。Note that the return value is Task<HttpResponseMessage> instead of Task<IEnumerable<string>> as would be more common for a GET api/values method. これは、カスタムの承認ロジックがコントローラー内にあることの副作用です。そのロジックの一部のエラー条件では、HTTP 応答オブジェクトをアドインのクライアントに送信することが必要になります。This is a side effect of that fact that our custom authorization logic will be in the controller: some error conditions in that logic require that an HTTP Response object be sent to the add-in's client.

    // GET api/values
    public async Task<HttpResponseMessage> Get()
    {
        // TODO1: Validate the scopes of the access token.
    }
    
  5. |||UNTRANSLATED_CONTENT_START|||Replace TODO1 with the following code to validate that the scopes that are specified in the token include access_as_user.|||UNTRANSLATED_CONTENT_END|||Replace TODO1 with the following code to validate that the scopes that are specified in the token include access_as_user.

    string[] addinScopes = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/scope").Value.Split(' ');
    if (addinScopes.Contains("access_as_user"))
    {
        // TODO2: Assemble all the information that is needed to get a token for Microsoft Graph using the "on behalf of" flow.
        // TODO3: Get the access token for Microsoft Graph.
        // TODO4: Get the names of files and folders in OneDrive by using the Microsoft Graph API.
        // TODO5: Remove excess information from the data and send the data to the client.
    }
    return SendErrorToClient(HttpStatusCode.Unauthorized, null, "Missing access_as_user.");
    

    注意

    注:access_as_user スコープだけを使用して、Office アドインの代理フローを処理する API を承認する必要があります。サービス内の他の API は、独自のスコープ要件が必要です。Note: You should only use the access_as_user scope to authorize the API that handles the on-behalf-of flow for Office add-ins. Other APIs in your service should have their own scope requirements. これにより、Office が取得するトークンでアクセスできるものが制限されます。This limits what can be accessed with the tokens that Office acquires.

  6. |||UNTRANSLATED_CONTENT_START|||Replace TODO2 with the following code. Note about this code:|||UNTRANSLATED_CONTENT_END|||Replace TODO2 with the following code. Note about this code:

    • このコードでは、Office ホストから受け取った Raw アクセス トークンを別のメソッドに渡される UserAssertion オブジェクトに変換します。It turns the raw access token received from the Office host into a UserAssertion object that will be passed to another method.
    • アドインは、Office ホストとユーザーがアクセスする必要のあるリソース (または対象ユーザー) の役割を果たさなくなります。この時点で、それ自体が Microsoft Graph にアクセスする必要があるクライアントになります。ConfidentialClientApplication は MSAL の「クライアント コンテキスト」オブジェクトになります。Your add-in is no longer playing the role of a resource (or audience) to which the Office host and user need access. Now it is itself a client that needs access to Microsoft Graph. ConfidentialClientApplication is the MSAL “client context” object.
    • コンストラクターへの 3 番目のパラメーターはリダイレクト URL です。これは、実際には「代理」フローで使用されることはありませんが、正しい URL を使用することをお勧めします。4 番目と 5 番目のパラメーターは、永続ストアを定義するために使用できます。このストアにより、有効期限が切れていないトークンをアドインの異なるセッション間で再使用できるようになります。このサンプルでは、永続ストアは実装していません。ConfidentialClientApplicationThe third parameter to the ConfidentialClientApplication constructor is a redirect URL which is not actually used in the “on behalf of” flow, but it is a good practice to use the correct URL. The fourth and fifth parameters can be used to define a persistent store that would enable the reuse of unexpired tokens across different sessions with the add-in. This sample does not implement any persistent storage.
    • MSAL では openidoffline_access の各スコープが機能することが必要ですが、コードがこれらを重複して要求するとエラーがスローされます。MSAL requires the openid and offline_access scopes to function, but it throws an error if your code redundantly requests them. コードが profile を要求した場合にもエラーがスローされます。それは、実際には Office ホスト アプリケーションがアドインの Web アプリケーションに対しトークンを取得するときだけに使用します。It will also throw an error if your code requests profile, which is really only used when the Office host application gets the token to your add-in's web application. そのため、Files.Read.All のみが明示的に要求されます。So only Files.Read.All is explicitly requested.

      var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as BootstrapContext;
      UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token);
      ClientCredential clientCred = new ClientCredential(ConfigurationManager.AppSettings["ida:Password"]);
      ConfidentialClientApplication cca =
                    new ConfidentialClientApplication(ConfigurationManager.AppSettings["ida:ClientID"],
                                                      "https://localhost:44355", clientCred, null, null);
      string[] graphScopes = { "Files.Read.All" };
      
  7. |||UNTRANSLATED_CONTENT_START|||Replace TODO3 with the following code. Note about this code:|||UNTRANSLATED_CONTENT_END|||Replace TODO3 with the following code. Note about this code:

    • メソッドは、最初にメモリ内の MSAL キャッシュで一致するアクセス トークンを探します。それが見つからなかった場合にのみ、Azure AD V2 エンドポイントとの「代理」フローを開始します。ConfidentialClientApplication.AcquireTokenOnBehalfOfAsyncThe ConfidentialClientApplication.AcquireTokenOnBehalfOfAsync method will first look in the MSAL cache, which is in memory, for a matching access token. Only if there isn't one, does it initiate the "on behalf of" flow with the Azure AD V2 endpoint.
    • MS Graph リソースが多要素認証を必要とし、ユーザーがまだそれを提供していない場合、AAD は Claims プロパティが含まれている例外をスローします。If multi-factor authentication is required by the MS Graph resource and the user has not yet provided it, AAD will throw an exception containing a Claims property.
    • Claims プロパティの値は、クライアントに渡す必要があります。クライアントは、その値を Office ホストに渡します。Office ホストは、その値を新しいトークンの要求に含めます。AAD は、認証のすべての必要なフォームをユーザーに示します。The Claims property value must be passed to the client which will pass it to the Office host, which will then include it in a request for a new token. AAD will prompt the user for all required forms of authentication.
    • 以外の種類の例外は、意図的にキャッチしていないため、500 Server Error メッセージとしてクライアントに伝達されます。MsalServiceExceptionAny exceptions that are not of type MsalServiceException are intentionally not caught, so they will propagate to the client as 500 Server Error messages.

      AuthenticationResult result = null;
      try
      {
        result = await cca.AcquireTokenOnBehalfOfAsync(graphScopes, userAssertion, "https://login.microsoftonline.com/common/oauth2/v2.0");
      }
      catch (MsalServiceException e)
      {        
        // TODO3a: Handle request for multi-factor authentication.
        // TODO3b: Handle lack of consent.
        // TODO3c: Handle invalid scope (permission).
        // TODO3d: Handle all other MsalServiceExceptions.
      }
      
  8. を次のコードに置き換えます。このコードの注意点は次のとおりです。TODO3aReplace TODO3a with the following code. Note about this code:

    • MS Graph リソースが多要素認証を必要としているときに、その認証をユーザーがまだ指定していない場合、AAD はエラー AADSTS50076 と Claims プロパティを含む "400 Bad Request" を返します。MSAL は MsalUiRequiredException (MsalServiceException から継承) をこの情報とともにスローします。If multi-factor authentication is required by the MS Graph resource and the user has not yet provided it, AAD will return "400 Bad Request" with error AADSTS50076 and a Claims property. MSAL throws a MsalUiRequiredException (which inherits from MsalServiceException) with this information.
    • Claims プロパティの値は、クライアントに渡す必要があります。クライアントは、その値を Office ホストに渡します。Office ホストは、その値を新しいトークンの要求に含めます。AAD は、認証のすべての必要なフォームのための指示をユーザーに示します。The Claims property value must be passed to the client which should pass it to the Office host, which then includes it in a request for a new token. AAD will prompt the user for all required forms of authentication.
    • 例外から HTTP 応答を作成する API は、Claims プロパティを認識しないため、このプロパティを応答オブジェクトに含めません。The APIs that create HTTP Responses from exceptions don't know about the Claims property, so they don't include it in the response object. これが含まれたメッセージを手動で作成する必要があります。We have to manually create a message that includes it. ただし、カスタムの Message プロパティは ExceptionMessage プロパティの作成を妨げるため、クライアントがエラー ID AADSTS50076 を取得するには、その ID をカスタムの Message に追加する以外に方法はありません。A custom Message property, however, blocks the creation of an ExceptionMessage property, so the only way to get the error ID AADSTS50076 to the client is to add it to the custom Message. クライアントの JavaScript では、応答に Message または ExceptionMessage が含まれているかどうかを検出する必要があるため、どちらを読み取るかを認識します。JavaScript in the client will need to discover if a response has a Message or ExceptionMessage, so it knows which to read.
    • カスタム メッセージは、JSON として書式設定されているため、クライアント側の JavaScript は既知の JSON オブジェクトのメソッドでメッセージを解析できます。The custom message is formatted as JSON so that the client-side JavaScript can parse it with well-known JSON object methods.
    • メソッドは、この後の手順で作成します。SendErrorToClientYou will create the SendErrorToClient method in a later step. 2 番目のパラメーターは、Exception オブジェクトです。It's second parameter is an Exception object. この場合、コードは null を渡します。これは、Exception オブジェクトが含まれていることで、生成される HTTP 応答には Message プロパティが含められなくなるためです。In this case, the code passes null because including the Exception object blocks the inclusion of the Message property in the HTTP Response that is generated.

      if (e.Message.StartsWith("AADSTS50076")) {
        string responseMessage = String.Format("{{\"AADError\":\"AADSTS50076\",\"Claims\":{0}}}", e.Claims);
        return SendErrorToClient(HttpStatusCode.Forbidden, null, responseMessage);
      }
      
  9. |||UNTRANSLATED_CONTENT_START|||Replace TODO3b and TODO3c with the following code. Note about this code:|||UNTRANSLATED_CONTENT_END|||Replace TODO3b and TODO3c with the following code. Note about this code:

    • AAD の呼び出しにユーザーまたはテナント管理者のどちらも同意していない (または同意が取り消された) スコープ (アクセス許可) が少なくとも 1 つ含まれていると、If the call to AAD contained at least one scope (permission) for which neither the user nor a tenant administrator has consented (or consent was revoked). AAD はエラー AADSTS65001 と共に "400 Bad Request" を返します。AAD will return "400 Bad Request" with error AADSTS65001. MSAL は、この情報と共に MsalUiRequiredException をスローします。MSAL throws a MsalUiRequiredException with this information. クライアントは、オプション { forceConsent: true } を使用して getAccessTokenAsync を再呼び出しする必要があります。The client should re-call getAccessTokenAsync with the option { forceConsent: true }.
    • AAD の呼び出しに AAD が認識しないスコープが少なくとも 1 つ含まれていると、AAD はエラー AADSTS70011 と共に "400 Bad Request" を返します。If the call to AAD contained at least one scope that AAD does not recognize, AAD returns "400 Bad Request" with error AADSTS70011. MSAL は、この情報と共に MsalUiRequiredException をスローします。MSAL throws a MsalUiRequiredException with this information. クライアントは、ユーザーに通知する必要があります。The client should inform the user.
    • すべての説明が含まれている理由は、別の条件で 70011 が返されたときに、このアドインでは無効なスコープの存在を意味する場合のみを処理する必要があるためです。The entire description is included beause 70011 is returned in other conditions and we it should only be handled in this add-in when it means that there is an invalid scope.
    • MsalUiRequiredException オブジェクトが SendErrorToClient に渡されます。これにより、エラー情報を格納している ExceptionMessage プロパティが HTTP 応答に含まれるようにします。The MsalUiRequiredException object is passed to SendErrorToClient. This ensures that an ExceptionMessage property that contains the error information is included in the HTTP Response.
    • カスタム メッセージは存在しないため、3 番目のパラメーターでは null が渡されます。There is no custom message, so null is passed for the third parameter.

      if ((e.Message.StartsWith("AADSTS65001"))
      || (e.Message.StartsWith("AADSTS70011: The provided value for the input parameter 'scope' is not valid.")))
      {
       return SendErrorToClient(HttpStatusCode.Forbidden, e, null);
      }
      
  10. を次のコードに置き換えます。TODO3dReplace TODO3d with the following code. このコードでは、HttpStatusCode.Forbidden (401) によるカスタムの HTTP 応答で例外を中継するのではなく、例外を再スローしています。Note that the code rethrows the exception instead of relaying it in a custom HTTP Response with HttpStatusCode.Forbidden (401). これにより、ASP.NET はステータス "500 Server Error" による独自の HTTP 応答を送信するようになります。The effect of this is that the ASP.NET will send its own HTTP Response with status "500 Server Error".

    else
    {
        throw e;
    }  
    
  11. |||UNTRANSLATED_CONTENT_START|||Replace TODO4 with the following. Note about this code:|||UNTRANSLATED_CONTENT_END|||Replace TODO4 with the following. Note about this code:

    • クラスと ODataHelper クラスは、[Helpers] フォルダー内のファイルで定義されています。OneDriveItem クラスは、[Models] フォルダー内のファイルで定義されています。これらのクラスについての詳しい説明は、承認や SSO に関連していないため、この記事の対象外になります。GraphApiHelperThe GraphApiHelper and ODataHelper classes are defined in files in the Helpers folder. The OneDriveItem class is defined in a file in the Models folder. Detailed discussion of these classes is not relevant to authorization or SSO, so it is out-of-scope for this article.
    • 実際に必要なデータのみを Microsoft Graph に要求することでパフォーマンスが向上します。そのため、このコードでは、$select クエリ パラメーターで name プロパティのみが必要なことを指定し、$top パラメーターで最初の 3 つのフォルダー名またはファイル名のみが必要なことを指定しています。Performance is improved by asking Microsoft Graph for only the data actually needed, so the code uses a $select query parameter to specify that we only want the name property, and a $top parameter to specify that we want only the first three folder or file names.
    • Microsoft Graph に送信したトークンが無効な場合、Microsoft Graph は、コード "InvalidAuthenticationToken" を含む "401 Unauthorized" エラーを送信します。If the token sent to Microsoft Graph is invalid, Microsoft Graph sends a "401 Unauthorized" error with the code "InvalidAuthenticationToken". その後で、ASP.NET は RuntimeBinderException をスローします。ASP.NET then throws a RuntimeBinderException. これは、トークンの有効期限が切れているときにも発生しますが、MSAL では、そのような事態にならないようにする必要があります。This is also what happens when the token is expired, although MSAL should prevent that from ever happening.
    var fullOneDriveItemsUrl = GraphApiHelper.GetOneDriveItemNamesUrl("?$select=name&$top=3");
    IEnumerable<OneDriveItem> filesResult;
    try
    {
        filesResult = await ODataHelper.GetItems<OneDriveItem>(fullOneDriveItemsUrl, result.AccessToken);
    }
    catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e)
    {
        return SendErrorToClient(HttpStatusCode.Unauthorized, e, null);                    
    }
    
  12. |||UNTRANSLATED_CONTENT_START|||Replace TODO5 with the following. Note about this code:|||UNTRANSLATED_CONTENT_END|||Replace TODO5 with the following. Note about this code:

    • 上記のコードでは OneDrive アイテムの name プロパティのみを要求していますが、Microsoft Graph は常に OneDrive アイテムの eTag プロパティを含めます。クライアントに送信するペイロードを縮小するために、次に示すコードではアイテム名のみで結果を再構築しています。Although the code above asked for only the name property of the OneDrive items, Microsoft Graph always includes the eTag property for OneDrive items. To reduce the payload sent to the client, the code below reconstructs the results with only the item names.
    • 3 つの OneDrive ファイルとフォルダーのリストは、"200 OK" HTTP 応答としてクライアントに送信されます。The list of three OneDrive files and folders is sent to the client as a "200 OK" HTTP Response.
    List<string> itemNames = new List<string>();
    foreach (OneDriveItem item in filesResult)
    {
        itemNames.Add(item.Name);
    }
    
    var requestMessage = new HttpRequestMessage();
    requestMessage.SetConfiguration(new HttpConfiguration());
    var response = requestMessage.CreateResponse<List<string>>(HttpStatusCode.OK, itemNames); 
    return response;
    
  13. Get メソッドの下に、次のメソッドを追加します。Below the Get method, add the following method. このコードの注意点は次のとおりです。About this code note:

    • このメソッドは、サーバー側の例外に関する情報をクライアントに中継します。The method relays to the client information about a server-side exception.
    • このメソッドに元の例外が渡されると、HttpError コンストラクターは例外オブジェクトからの情報を ExceptionMessage プロパティに含めます。If the original exception is passed to the method, then the HttpError constuctor will include information from the exception object in an ExceptionMessage property.
    • 例外として null が渡されると、HttpError コンストラクターはメッセージ パラメーターを Message プロパティに含めます。ExceptionMessage プロパティは存在しなくなります。If null is passed for the exception, then the HttpError constuctor will include the message parameter in a Message property and there is no ExceptionMessage property.
    private HttpResponseMessage SendErrorToClient(HttpStatusCode statusCode, Exception e, string message)
    {
        HttpError error;
        if (e != null)
        {
            error = new HttpError(e, true);
        }
        else
        {
            error = new HttpError(message);
        }
        var requestMessage = new HttpRequestMessage();
        var errorMessage = requestMessage.CreateErrorResponse(statusCode, error);
        return errorMessage;
    }        
    

アドインを実行するRun the add-in

  1. 結果を確認できるように、OneDrive 内にファイルがいくつかあることを確認します。Ensure that you have some files in your OneDrive so that you can verify the results.

  2. Visual Studio で、F5 キーを押します。PowerPoint が開き、[ホーム] リボンに [SSO ASP.NET] グループが表示されます。In Visual Studio, press F5. PowerPoint opens and there is an SSO ASP.NET group on the Home ribbon.

  3. このグループ内の [アドインの表示] ボタンをクリックすると、作業ウィンドウにアドインの UI が表示されます。Press the Show Add-in button in this group to see the add-in’s UI in the task pane.

  4. [OneDrive からファイルを取得] ボタンをクリックします。Office にサインインしていない場合は、サインインを求めるダイアログが表示されます。Press the button Get My Files from OneDrive. If you are not signed into Office, you'll be prompted to sign in.

    注意

    以前に別の ID で Office にサインオンしていて、そのときに開いたいくつかの Office アプリケーションが引き続き開いている場合、Office がその ID を確実に変更するとは限りません (PowerPoint で ID が変更済みのように表示されている場合でも)。If you were previously signed on to Office with a different ID, and some Office applications that were open at the time are still open, Office may not reliably change your ID even if it appears to have done so in PowerPoint. このような場合は、Microsoft Graph への呼び出しが失敗するか、以前の ID からのデータが返される可能性があります。If this happens, the call to Microsoft Graph may fail or data from the previous ID may be returned. これを防止するには、必ず他のすべての Office アプリケーションを閉じてから、[OneDrive からファイルを取得] を押します。To prevent this, be sure to close all other Office applications before you press Get My Files from OneDrive.

  5. サインインすると、ボタンの下に OneDrive のファイルとフォルダーのリストが表示されます。これには、15 秒以上かかることがあります (特に初回実行時)。After you are signed in, a list of your files and folders on OneDrive will appear below the button. This may take over 15 seconds, especially the first time.