🔗

Microsoft.Identity.Web のダウンストリーム API を使ってみる

に公開

はじめに

Microsoft.Identity.Web は ASP.NET Core に Microsoft Entra ID を統合する方法を提供します。Web API を保護する方法として Azure App Service の認証と承認機能 (EasyAuth) を使うこともできますが、動作確認には Azure にデプロイする必要があります。既存のコードを修正できない Web API を保護する場合を除き、Microsoft.Identity.Web を使用するほうが開発上のメリットが大きくなります。Microsoft.Identity.Web ではローカルでデバッグ実行できることに加え、ダウンストリーム API を使ってほかの Web API を呼び出すことができます。ダウンストリーム API では、自身の認証に使用したアクセス トークンをほかの Web API のアクセス トークンに変換して呼び出します。この仕組みはトークン変換 (Token Exchange) と呼ばれます。ダウンストリーム API のシナリオには、次のようなものがあります。

API の種類 パッケージ
Azure SDK Microsoft.Identity.Web.Azure
Microsoft Graph API Microsoft.Identity.Web.MicrosoftGraph
カスタム API Microsoft.Identity.Web.DownstreamApi

詳細については Microsoft Learn のドキュメントも参考にしてください。

https://learn.microsoft.com/ja-jp/entra/msidweb/call-downstream-apis/overview?WT.mc_id=M365-MVP-5002941

今回の記事では、Microsoft Graph API とカスタム API を呼び出す方法を確認します。

サンプル コード

https://github.com/karamem0/samples/tree/main/aspnet-downstreaming-apis

実行手順

事前準備

Microsoft Entra ID アプリケーションの登録 (クライアント)

クライアントの Microsoft Entra ID アプリケーションを登録します。合わせてシークレットを作成します。

項目
名前 SampleApplication Client
サポートされているアカウントの種類 シングル テナントのみ
リダイレクト URI Web
http://localhost

Microsoft Entra ID アプリケーションの登録 (Web API)

Web API の Microsoft Entra ID アプリケーションを登録します。合わせてシークレットを作成します。

項目
名前 SampleApplication Web API
サポートされているアカウントの種類 シングル テナントのみ
リダイレクト URI (なし)

Web API が使用する API のアクセス許可を構成します。また管理者としてアクセス許可を同意します。

項目
Microsoft Graph User.Read
SharePoint User.Read.All

Web API を公開します。

項目
スコープ名 access_as_user
同意できるのはだれですか? 管理者とユーザー
管理者の同意の表示名 access_as_user
管理者の同意の説明 サインインしたユーザーの代わりに Web API を呼び出します。
ユーザーの同意の表示名 access_as_user
ユーザーの同意の説明 サインインしたユーザーの代わりに Web API を呼び出します。
状態 有効

Web API をクライアントからアクセスできるように構成します。

項目
クライアント ID <クライアント アプリのクライアント ID>
承認済みのスコープ api:/<Web API アプリのクライアント ID>/access_as_user

プロジェクトの作成

ASP.NET Core Web API プロジェクトを作成します。

dotnet new webapi

必要なパッケージを追加します。

dotnet add package Microsoft.Identity.Web.MicrosoftGraph
dotnet add package Microsoft.Identity.Web.DownstreamApi

Microsoft Graph API

Program.cs

AddMicrosoftIdentityWebApiAuthentication メソッドを呼び出します。これは AddMicrosoftIdentityWebApi メソッドと AddAuthentication メソッドをまとめたものです。これらにより Web API が Microsoft Entra ID によって保護されます。続けて EnableTokenAcquisitionToCallDownstreamApi メソッドを呼び出します。これによりダウンストリーム API を使用できるようになります。その後、AddMicrosoftGraph メソッドを呼び出すことで GraphServiceClient クラスを依存関係として注入できるようになります。API の実装では GraphServiceClient クラスを受け取ることで Microsoft Graph API を呼び出せます。API を保護するため、RequireAuthorization メソッドを呼び出すようにします。

var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
var services = builder.Services;
_ = services
    .AddMicrosoftIdentityWebApiAuthentication(configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddMicrosoftGraph(configuration.GetSection("MicrosoftGraph"))
    .AddInMemoryTokenCaches();

var app = builder.Build();

...

app.MapGet("/api/graph/me", async (Microsoft.Graph.GraphServiceClient client) =>
    {
        var user = await client.Me.Request().GetAsync();
        return new UserInfo(
            user.Id,
            user.UserPrincipalName,
            user.DisplayName,
            user.Mail
        );
    })
    .RequireAuthorization();

appsettings.json

Web API の Microsoft Entra ID アプリケーションの情報および Microsoft Graph API の情報を設定します。

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "{{tenant-id}}",
    "ClientId": "{{client-id}}",
    "ClientSecret": "{{client-secret}}"
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": [
      "User.Read"
    ]
  }
}

カスタム API

Program.cs

今回はカスタム API として SharePoint REST API を使用します。カスタム API の場合も大きな流れは同じです。AddDownstreamApi メソッドを呼び出すことで IDownstreamApi インターフェースを依存関係として注入できるようになります。AddDownstreamApi はサービス名をキーにして複数のサービスを登録できます。API から呼び出すときもサービス名を指定します。

var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
var services = builder.Services;
_ = services
    .AddMicrosoftIdentityWebApiAuthentication(configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("SharePoint", configuration.GetSection("SharePoint"))
    .AddInMemoryTokenCaches();

var app = builder.Build();

...

app.MapGet("/api/sharepoint/me", async (IDownstreamApi client) =>
    {
        var response = await client.CallApiForUserAsync(
            "SharePoint",
            options =>
            {
                options.HttpMethod = "POST";
                options.AcceptHeader = "application/json;odata=nometadata";
                options.RelativePath = "_api/sp.userprofiles.profileloader.getprofileloader/getuserprofile";
            }
        );
        var user = await response.Content.ReadFromJsonAsync<UserProfile>();
        return new UserInfo(
            user?.AccountName,
            user?.AccountName?.Split('|').LastOrDefault(),
            user?.DisplayName,
            user?.SipAddress
        );
    })
    .RequireAuthorization();

appsettings.json

Web API の Microsoft Entra ID アプリケーションの情報およびカスタム API の情報を設定します。00000003-0000-0ff1-ce00-000000000000 は SharePoint Online のアプリケーション ID です。カスタム API の場合、スコープは {{resource-uri}}/{{scope-name}} または {{application-id}}/{{scope-name}} の形式です。スコープは配列で指定する必要があります。

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "{{tenant-id}}",
    "ClientId": "{{client-id}}",
    "ClientSecret": "{{client-secret}}"
  },
  "SharePoint": {
    "BaseUrl": "https://{{tenant-name}}.sharepoint.com/",
    "Scopes": [
      "00000003-0000-0ff1-ce00-000000000000/User.Read.All"
    ]
  }
}

実行結果

実際に Postman を使って API を呼び出します。Microsoft Graph API の場合は、次のような結果を取得できます。

{
    "id": "b93a9078-...",
    "userPrincipalName": "mebanb@contoso.com",
    "displayName": "Megan Bowen",
    "mail": "mebanb@contoso.com"
}

SharePoint の場合も結果を取得できます。

{
    "id": "i:0#.f|membership|mebanb@contoso.com",
    "userPrincipalName": "mebanb@contoso.com",
    "displayName": "Megan Bowen",
    "mail": "mebanb@contoso.com"
}

おわりに

シングルページ アプリケーション (SPA) から複数のサービスを呼び出す場合、サービスごとにアクセス トークンを取得する必要があり、実装が煩雑になることがあります。ダウンストリーム API を使うことで、複数のサービスに切り替えてデータ操作をすることが簡単になります。Web API にドメイン モデルを実装することで、クライアントからの操作がしやすくなるため、ぜひ活用してみてください。

Discussion