Windows (UWP) アプリに認証を追加する

このチュートリアルでは、Microsoft Entra ID を使用して、TodoApp プロジェクトに Microsoft 認証を追加します。 このチュートリアルを完了する前に、プロジェクトを作成し、バックエンドをデプロイしていることを確認してください。

ヒント

ここでは認証に Microsoft Entra ID を使用しますが、Azure Mobile Apps では任意の認証ライブラリを使用できます。

バックエンド サービスに認証を追加する

バックエンド サービスは標準の ASP.NET 6 サービスです。 ASP.NET 6 サービスで認証を有効にする方法を示すチュートリアルはすべて、Azure Mobile Apps にも適用できます。

バックエンド サービスに対して Microsoft Entra 認証を有効にするには、次の手順を実行する必要があります。

  • Microsoft Entra ID でアプリケーションを登録します。
  • ASP.NET 6 バックエンド プロジェクトに認証チェックを追加します。

アプリケーションを登録する

まず、Microsoft Entra テナントに Web API を登録し、次の手順に従ってスコープを追加します:

  1. Azure portal にサインインします。

  2. 複数のテナントにアクセスできる場合は、トップ メニューの [ディレクトリとサブスクリプション] フィルターを使用して、アプリケーションを登録するテナントに切り替えます。

  3. Microsoft Entra ID を検索して選択します。

  4. [管理][アプリの登録]>[新規登録] の順に選択します。

    • 名前: 登録するアプリケーションの名前を入力します。たとえば、TodoApp Quickstart など。 このアプリのユーザーには、この名前が表示されます。 これは後で変更できます。
    • サポートされているアカウントの種類: 任意の組織のディレクトリ内のアカウント (任意の Microsoft Entra ディレクトリ - マルチテナント) と個人の Microsoft アカウント (Skype、Xbox など)
  5. 登録 を選択します。

  6. [管理] で、 [API の公開]>[スコープの追加] の順に選択します。

  7. [アプリケーション ID URI] は既定値のままにして [保存して続行] を選択します。

  8. 次の詳細情報を入力します:

    • スコープ名: access_as_user
    • 同意できるのはだれですか? : 管理者とユーザー
    • 管理者の同意の表示名: Access TodoApp
    • 管理者の同意の説明: Allows the app to access TodoApp as the signed-in user.
    • ユーザーの同意の表示名: Access TodoApp
    • ユーザーの同意の説明: Allow the app to access TodoApp on your behalf.
    • [状態] :有効
  9. [スコープの追加] を選択してスコープの追加を完了します。

  10. api://<client-id>/access_as_user のようなスコープの値を書き留めます (Web API スコープ と呼ばれます)。 このスコープは、クライアントを構成するときに必要になります。

  11. [概要] を選択します。

  12. [Essentials] セクションの [アプリケーション (クライアント) ID] を書き留めます (Web API アプリケーション ID と呼ばれます)。 この値は、バックエンド サービスを構成するときに必要になります。

Visual Studio を開いて、TodoAppService.NET6 プロジェクトを選択します。

  1. TodoAppService.NET6 プロジェクトを右クリックし、[NuGet パッケージの管理] を選択します。

  2. 新しいタブで [参照] を選択し、検索ボックスに「Microsoft.Identity.Web」と入力します。

    Screenshot of adding the M S A L NuGet in Visual Studio.

  3. Microsoft.Identity.Web パッケージを選択し、[インストール] を押します。

  4. 指示に従ってパッケージのインストールを完了します。

  5. Program.cs を開きます。 using ステートメントの一覧に以下を追加します。

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
  1. builder.Services.AddDbContext() の呼び出しのすぐ上に次のコードを追加します。
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddMicrosoftIdentityWebApi(builder.Configuration);
builder.Services.AddAuthorization();
  1. app.MapControllers() の呼び出しのすぐ上に次のコードを追加します。
app.UseAuthentication();
app.UseAuthorization();

Program.cs は次のようになります。

using Microsoft.AspNetCore.Datasync;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using TodoAppService.NET6.Db;
  
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
  
if (connectionString == null)
{
  throw new ApplicationException("DefaultConnection is not set");
}
  
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddMicrosoftIdentityWebApi(builder.Configuration);
builder.Services.AddAuthorization();
builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDatasyncControllers();
  
var app = builder.Build();
  
// Initialize the database
using (var scope = app.Services.CreateScope())
{
  var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
  await context.InitializeDatabaseAsync().ConfigureAwait(false);
}
  
// Configure and run the web service.
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
  1. Controllers\TodoItemController.cs を編集します。 クラスに [Authorize] 属性を追加します。 クラスは次のようになります。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Datasync;
using Microsoft.AspNetCore.Datasync.EFCore;
using Microsoft.AspNetCore.Mvc;
using TodoAppService.NET6.Db;

namespace TodoAppService.NET6.Controllers
{
  [Authorize]
  [Route("tables/todoitem")]
  public class TodoItemController : TableController<TodoItem>
  {
    public TodoItemController(AppDbContext context)
      : base(new EntityTableRepository<TodoItem>(context))
    {
    }
  }
}
  1. appsettings.json を編集します。 次のブロックを追加します。
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com",
    "ClientId": "<client-id>",
    "TenantId": "common"
  },

<client-id> を、前に記録した "Web API アプリケーション ID" に置き換えます。 完了すると、次のようになります。

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com",
    "ClientId": "<client-id>",
    "TenantId": "common"
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=TodoApp;Trusted_Connection=True"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

サービスを Azure に再発行します。

  1. TodoAppService.NET6 プロジェクトを右クリックし、[パブリッシュ] を選択します。
  2. タブの右上隅にある [パブリッシュ] ボタンを選択します。

https://yoursite.azurewebsites.net/tables/todoitem?ZUMO-API-VERSION=3.0.0 を指定してブラウザーを開きます。 ここで、このサービスは 401 の応答を返すことに注意して下さい。これは、認証が必要であることを示しています。

Screenshot of the browser showing an error.

アプリを ID サービスに登録する

Microsoft Data sync Framework には、HTTP トランザクションのヘッダー内で JSON Web トークン (JWT) を使用する認証プロバイダーのサポートが組み込まれています。 このアプリケーションでは、Microsoft 認証ライブラリ (MSAL) を使用してそのようなトークンを要求し、サインインしているユーザーをバックエンド サービスに対して承認します。

ネイティブ クライアント アプリケーションを構成する

Microsoft ID ライブラリ (MSAL) などのクライアント ライブラリを使用してアプリでホストされている Web API への認証を許可するように、ネイティブ クライアントを登録できます。

  1. Azure portal で、[Microsoft Entra ID]>[アプリの登録]>[新規登録] の順に選択します。

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

    • アプリケーション登録用の[名前]を入力します。 バックエンド サービスで使用される名前と区別するために、名前は native-quickstart の使用をお勧めします。
    • 任意の組織のディレクトリ (Microsoft Entra ディレクトリ - マルチテナント) 内のアカウントと、個人用の Microsoft アカウント (Skype、Xbox など) を選択します。
    • [リダイレクト URI] は次のようにします。
      • [パブリック クライアント] (モバイルとデスクトップ) の選択
      • URL quickstart://auth を入力します。
  3. 登録 を選択します。

  4. [API のアクセス許可][アクセス許可の追加][自分の API] の順に選択します。

  5. 以前にバックエンド サービス用に作成したアプリ登録を選択します。 アプリ登録が表示されない場合は、access_as_user スコープを追加しているかを確認します。

    Screenshot of the scope registration in the Azure portal.

  6. [アクセス許可の選択] で [access_as_user] を選択してから、[アクセス許可の追加] を選択します。

  7. [認証] > [モバイル アプリケーションとデスクトップ アプリケーション] の順に選択します。

  8. https://login.microsoftonline.com/common/oauth2/nativeclient の横にあるチェック ボックスをオンにします。

  9. msal{client-id}://auth の横にあるチェック ボックスをオンにします ({client-id} をアプリケーション ID に置き換える)。

  10. [URI の追加] を選択し、追加 URI のフィールドに http://localhost を追加します。

  11. ページの下部にある [保存] を選択します。

  12. [概要] を選択します。 [アプリケーション (クライアント) ID] を書き留めます (ネイティブ クライアント アプリケーション ID と呼ばれます)。これは、モバイル アプリを構成するときに必要になります。

次の 3 つのリダイレクト URL を定義しました。

  • http://localhost は WPF アプリケーションで使用されます。
  • https://login.microsoftonline.com/common/oauth2/nativeclient は UWP アプリケーションで使用されます。
  • msal{client-id}://auth は、モバイル (Android および iOS) アプリケーションで使用されます。

Microsoft Identity Client をアプリに追加する

TodoApp.sln ソリューションを Visual Studio で開き、TodoApp.UWP プロジェクトをスタートアップ プロジェクトとして設定します。 Microsoft Identity Library (MSAL)TodoApp.UWP プロジェクトに追加します。

Microsoft Identity Library (MSAL) をプラットフォーム プロジェクトに追加します。

  1. プロジェクトを右クリックし、[NuGet パッケージの管理] を選択します。

  2. [参照] タブを選択します。

  3. 検索ボックスに「Microsoft.Identity.Client」と入力し、Enter キーを押します。

  4. Microsoft.Identity.Client の結果を選択し、[インストール] をクリックします。

    Screenshot of selecting the MSAL NuGet in Visual Studio.

  5. 使用許諾契約書に同意してインストールを続行します。

ネイティブ クライアント ID とバックエンド スコープを構成に追加します。

TodoApp.Data プロジェクトを開き、Constants.cs ファイルを編集します。 ApplicationIdScopes の定数を追加します。

  public static class Constants
  {
      /// <summary>
      /// The base URI for the Datasync service.
      /// </summary>
      public static string ServiceUri = "https://demo-datasync-quickstart.azurewebsites.net";

      /// <summary>
      /// The application (client) ID for the native app within Microsoft Entra ID
      /// </summary>
      public static string ApplicationId = "<client-id>";

      /// <summary>
      /// The list of scopes to request
      /// </summary>
      public static string[] Scopes = new[]
      {
          "<scope>"
      };
  }

<client-id> を、クライアント アプリケーションを Microsoft Entra ID に登録するときに受け取った ネイティブ クライアント アプリケーション ID に置き換えます。次に <scope> を、サービス アプリケーションの登録時に [API の公開] を使用したときにコピーした Web API スコープ に置き換えます。

TodoApp.UWP プロジェクトの App.xaml.cs ファイルを開きます。

次の using ステートメントをファイルの先頭に追加します。

using Microsoft.Datasync.Client;
using Microsoft.Identity.Client;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

コンストラクターと TodoService コードを以下のコードに置き換えます。

public App()
{
    InitializeComponent();
    Suspending += OnSuspending;

    IdentityClient = GetIdentityClient();
    TodoService = new RemoteTodoService(GetAuthenticationToken);
}

public static IPublicClientApplication IdentityClient { get; set; }

public ITodoService TodoService { get; }

public IPublicClientApplication GetIdentityClient()
{
    var identityClient = PublicClientApplicationBuilder.Create(Constants.ApplicationId)
        .WithAuthority(AzureCloudInstance.AzurePublic, "common")
        .WithUseCorporateNetwork(false)
        .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
        .Build();
    return identityClient;
}

public async Task<AuthenticationToken> GetAuthenticationToken()
{
    var accounts = await IdentityClient.GetAccountsAsync();
    AuthenticationResult result = null;
    bool tryInteractiveLogin = false;

    try
    {
        result = await IdentityClient
            .AcquireTokenSilent(Constants.Scopes, accounts.FirstOrDefault())
            .ExecuteAsync()
            .ConfigureAwait(false);
    }
    catch (MsalUiRequiredException)
    {
        tryInteractiveLogin = true;
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"MSAL Silent Error: {ex.Message}");
    }

    if (tryInteractiveLogin)
    {
        try
        {
            result = await IdentityClient
                .AcquireTokenInteractive(Constants.Scopes)
                .ExecuteAsync()
                .ConfigureAwait(false);
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"MSAL Interactive Error: {ex.Message}");
        }
    }

    return new AuthenticationToken
    {
        DisplayName = result?.Account?.Username ?? "",
        ExpiresOn = result?.ExpiresOn ?? DateTimeOffset.MinValue,
        Token = result?.AccessToken ?? "",
        UserId = result?.Account?.Username ?? ""
    };
}

GetAuthenticationToken() メソッドは Microsoft Identity Library (MSAL) と連携して、サインインしているユーザーのバックエンド サービスへの認証に適したアクセス トークンを取得します。 この関数は、クライアント作成のために RemoteTodoService に渡されます。 認証が成功すると、各要求の認証に必要なデータと共に AuthenticationToken が生成されます。 成功しなかった場合は、代わりに期限切れの無効なトークンが生成されます。

アプリをテストする

F5 キーを押すことで、アプリを実行できます。 アプリが実行されるとブラウザーが開き、ユーザーは認証を求められます。 アプリを初めて実行する場合、ユーザーはアクセスに同意するように求められます。

Screenshot of the Microsoft Entra consent request.

[はい] を押して、アプリを続行します。

次のステップ

次に、オフライン ストアを実装して、オフラインで動作するようにアプリケーションを構成します。

参考資料