次の方法で共有


チュートリアル: 外部テナントを使用して .NET MAUI シェル アプリでユーザーをサインインさせる

このチュートリアルは、.NET Multi-Platform App UI (.NET MAUI) シェル アプリを作成し、Microsoft Entra 管理センターを使用した認証のためにそれを準備する方法を見ていくシリーズの、最後のパートです。 このシリーズのパート 2 では、カスタム Microsoft Authentication Library (MSAL) クライアント ヘルパーを追加して MSAL SDK を初期化し、必要なライブラリをインストールして、画像リソースを含めました。 この最後のステップでは、.NET MAUI にサインインとサインアウトのコードを追加し、Android プラットフォームでシェル アプリを実行する方法を見ていきます。

このチュートリアルでは、次のことについて説明します。

  • サインインとサインアウト コードを追加します。
  • アプリ シェルを変更します。
  • プラットフォーム固有のコードを追加します。
  • アプリ設定を追加します。
  • .NET MAUI シェル アプリを実行してテストします。

前提条件

サインインとサインアウト コードを追加する

.NET MAUI アプリのユーザー インターフェイス (UI) は、各ターゲット プラットフォームのネイティブ コントロールにマップされるオブジェクトで構成されています。 .NET MAUI アプリの UI の作成に使用される主なコントロール グループは、ページ、レイアウト、ビューです。

メイン ビュー ページを追加する

次の手順では、main view が定義されるようにコードを組みます。

  1. プロジェクトから MainPage.xamlMainPage.xaml.cs を削除します。これらはもう必要ありません。 [ソリューション エクスプローラー] ペインで、[MainPage.xaml] のエントリを見つけて、右クリックして [削除] を選択します。

  2. [SignInMaui] プロジェクトで右クリックし、[追加]>[新しいフォルダー] を選択します。 フォルダーの名前を [Views] にします。

  3. [Views] で右クリックします。

  4. [追加]>[新しい項目...] を選択します。

  5. テンプレートの一覧で [.NET MAUI] を選択します。

  6. [.NET MAUI ContentPage (XAML)] テンプレートを選択します。 ファイルの名前を [MainView.xaml] にします。

  7. [追加] を選択します。

  8. MainView.xaml ファイルが新しいドキュメント タブで開き、ページの UI を表すすべての XAML マークアップが表示されます。 XAML マークアップを次のマークアップで置き換えます。

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="SignInMaui.Views.MainView"
                 Title="Microsoft identity platform"
                 >
        <Shell.BackButtonBehavior>
            <BackButtonBehavior IsVisible="False" IsEnabled="False" />
        </Shell.BackButtonBehavior>
    
        <ScrollView>
            <VerticalStackLayout 
                Spacing="25" 
                Padding="30,0" 
                VerticalOptions="Center">
    
                <Image
                    Source="azure_active_directory.png"
                    SemanticProperties.Description="Azure Active Directory Logo"
                    HeightRequest="200"
                    HorizontalOptions="Center" />
    
                <Label 
                    Text="Azure AD for Customers"
                    SemanticProperties.HeadingLevel="Level1"
                    FontSize="26"
                    HorizontalOptions="Center" />
    
                <Label 
                    Text="MAUI sample"
                    SemanticProperties.HeadingLevel="Level1"
                    FontSize="26"
                    HorizontalOptions="Center" />
    
                <Button 
                    x:Name="SignInButton"
                    Text="Sign In"
                    SemanticProperties.Hint="Sign In"
                    Clicked="OnSignInClicked"
                    HorizontalOptions="Center"
                    IsEnabled="False"/>
    
            </VerticalStackLayout>
        </ScrollView>
     
    </ContentPage>
    
  9. ファイルを保存します。

    以下でページに配置された XAML コントロールの主要なパーツを理解しましょう。

    • <ContentPage> は MainView クラスのルート オブジェクトです。
    • <VerticalStackLayout> は ContentPage の子オブジェクトです。 このレイアウト コントロールは、子要素を垂直方向に順番に配置します。
    • <Image> は画像を表示します。この場合は、前にダウンロードした azureactive_directory.png_ を使用しています。
    • <Label> コントロールはテキストを表示します。
    • <Button> はユーザーが押すことができ、これによって Clicked イベントが発生します。 Clicked イベントに応じてコードを実行できます。
    • Clicked="OnSignInClicked" ボタンの Clicked イベントは OnSignInClicked イベント ハンドラーに割り当てられ、これは分離コード ファイルで定義されます。 このコードを次の手順で作成します。

OnSignInClicked イベントを処理する

次の手順は、ボタンの Clicked イベントのコードを追加することです。

  1. Visual Studio の [ソリューション エクスプローラー] ペインで、[MainView.xaml] ファイルを展開して、分離コード ファイル [MainView.xaml.cs] を表示します。 [MainView.xaml.cs] を開き、ファイルの内容を次のコードで置き換えます。

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    
    using SignInMaui.MSALClient;
    using Microsoft.Identity.Client;
    
    namespace SignInMaui.Views
    {
        public partial class MainView : ContentPage
        {
            public MainView()
            {
                InitializeComponent();
    
                IAccount cachedUserAccount = PublicClientSingleton.Instance.MSALClientHelper.FetchSignedInUserFromCache().Result;
    
                _ = Dispatcher.DispatchAsync(async () =>
                {
                    if (cachedUserAccount == null)
                    {
                        SignInButton.IsEnabled = true;
                    }
                    else
                    {
                        await Shell.Current.GoToAsync("claimsview");
                    }
                });
            }
    
            private async void OnSignInClicked(object sender, EventArgs e)
            {
                await PublicClientSingleton.Instance.AcquireTokenSilentAsync();
                await Shell.Current.GoToAsync("claimsview");
            }
            protected override bool OnBackButtonPressed() { return true; }
    
        }
    }
    

    MainView クラスは、アプリのメイン ビューを表示するコンテンツ ページです。 コンストラクターでは、キャッシュされたユーザー アカウントが見つからない場合、PublicClientSingleton インスタンスからの MSALClientHelper を使用してキャッシュされたユーザー アカウントを取得しサインイン ボタンを有効にします。

    サインイン ボタンがクリックされると、AcquireTokenSilentAsync メソッドを呼び出してトークンをサイレントで取得し、Shell.Current.GoToAsync メソッドを使用して claimsview ページに遷移します。 さらに、OnBackButtonPressed メソッドは true を返すようにオーバーライドされるので、このビューの戻るボタンは無効になります。

要求ビュー ページを追加する

次の手順では、ClaimsView ページが定義されるようにコードを組みます。 ページには、ID トークンで見つかったユーザーの要求が表示されます。

  1. Visual Studio の [ソリューション エクスプローラー] ペインで、[Views] を右クリックします。

  2. [追加]>[新しい項目...] を選択します。

  3. テンプレートの一覧で [.NET MAUI] を選択します。

  4. [.NET MAUI ContentPage (XAML)] テンプレートを選択します。 ファイルの名前を [ClaimsView.xaml] にします。

  5. [追加] を選択します。

  6. ClaimsView.xaml ファイルが新しいドキュメント タブで開き、ページの UI を表すすべての XAML マークアップが表示されます。 XAML マークアップを次のマークアップで置き換えます。

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="SignInMaui.Views.ClaimsView"
                 Title="ID Token View">
        <Shell.BackButtonBehavior>
            <BackButtonBehavior IsVisible="False" IsEnabled="False" />
        </Shell.BackButtonBehavior>
        <VerticalStackLayout>
            <Label 
                Text="Azure AD for Customers"
                FontSize="26"
                HorizontalOptions="Center" />
            <Label 
                Text="MAUI sample"
                FontSize="26"
                Padding="0,0,0,20"
                HorizontalOptions="Center" />
    
            <Label 
                Padding="0,20,0,0"
                VerticalOptions="Center" 
                HorizontalOptions="Center"
                FontSize="18"
                Text="Claims found in ID token"
                />
            <ListView ItemsSource="{Binding IdTokenClaims}"
                      x:Name="Claims">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid Padding="0, 0, 0, 0">
                                <Label Grid.Column="1" 
                                       Text="{Binding}" 
                                       HorizontalOptions="Center" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <Button
                x:Name="SignOutButton"
                Text="Sign Out"
                HorizontalOptions="Center"
                Clicked="SignOutButton_Clicked" />
        </VerticalStackLayout>
    </ContentPage>
    

    この XAML マークアップ コードは、.NET MAUI アプリの要求ビューの UI レイアウトを表します。 まず、ContentPage をタイトルで定義し、戻るボタンの動作を無効にします。

    VerticalStackLayout 内には、静的テキストを表示するいくつかの Label 要素があり、その後に Claims という名前の ListView が続き、ID トークンで見つかった要求を表示するための IdTokenClaims というコレクションにバインドされます。 各要求は、ViewCell 内で DataTemplate を使用してレンダリングされ、グリッド内で中央揃えの Label として表示されます。

    最後に、レイアウトの下部の中央に Sign Out ボタンがあり、クリックされると SignOutButton_Clicked イベント ハンドラーがトリガーされます。

ClaimsView データを処理する

次の手順は、ClaimsView データを処理するためのコードを追加することです。

  1. Visual Studio の [ソリューション エクスプローラー] ペインで、[ClaimsView.xaml] ファイルを展開して、分離コード ファイル [ClaimsView.xaml.cs] を表示します。 [ClaimsView.xaml.cs] を開き、ファイルの内容を次のコードで置き換えます。

    using SignInMaui.MSALClient;
    using Microsoft.Identity.Client;
    
    namespace SignInMaui.Views;
    
    public partial class ClaimsView : ContentPage
    {
        public IEnumerable<string> IdTokenClaims { get; set; } = new string[] {"No claims found in ID token"};
        public ClaimsView()
        {
            BindingContext = this;
            InitializeComponent();
    
            _ = SetViewDataAsync();
        }
    
        private async Task SetViewDataAsync()
        {
            try
            {
                _ = await PublicClientSingleton.Instance.AcquireTokenSilentAsync();
    
                IdTokenClaims = PublicClientSingleton.Instance.MSALClientHelper.AuthResult.ClaimsPrincipal.Claims.Select(c => c.Value);
    
                Claims.ItemsSource = IdTokenClaims;
            }
    
            catch (MsalUiRequiredException)
            {
                await Shell.Current.GoToAsync("claimsview");
            }
        }
    
        protected override bool OnBackButtonPressed() { return true; }
    
        private async void SignOutButton_Clicked(object sender, EventArgs e)
        {
            await PublicClientSingleton.Instance.SignOutAsync().ContinueWith((t) =>
            {
                return Task.CompletedTask;
            });
    
            await Shell.Current.GoToAsync("mainview");
        }
    }
    

    ClaimsView.xaml.cs コードは、.NET MAUI アプリの要求ビューの分離コードを表します。 まず、必要な名前空間をインポートし、ContentPage を拡張する ClaimsView クラスを定義します。 IdTokenClaims プロパティは文字列の Enumerable であり、最初はクレームが見つからないことを示す 1 つの文字列に設定されています。

    ClaimsView コンストラクターは、バインディング コンテキストを現在のインスタンスに設定し、ビュー コンポーネントを初期化し、SetViewDataAsync メソッドを非同期的に呼び出します。 SetViewDataAsync メソッドは、トークンのサイレントな取得を試み、認証結果から要求を取得し、それらを Claims という名前の ListView に表示するために IdTokenClaims プロパティを設定します。 認証にユーザー操作が必要であることを示す MsalUiRequiredException が発生した場合、アプリは要求ビューに遷移します。

    OnBackButtonPressed メソッドは、戻るボタンの動作を常に true を返すようにオーバーライドして、ユーザーがこのビューから戻る動作をできないようにします。 SignOutButton_Clicked イベント ハンドラーは、PublicClientSingleton インスタンスを使用してユーザーをサインアウトし、完了すると main view に遷移します。

アプリ シェルを変更する

AppShell クラスは、アプリのビジュアル階層、つまりアプリの UI の作成に使用される XAML マークアップを定義します。 AppShellViews について知ることができるように、これを更新します。

  1. [ソリューション エクスプローラー] ペインで AppShell.xaml ファイルをダブルクリックして、XAML エディターを開きます。 XAML マークアップを次のコードで置き換えます。

    <?xml version="1.0" encoding="UTF-8" ?>
    <Shell
        x:Class="SignInMaui.AppShell"
        xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:local="clr-namespace:SignInMaui.Views"
        Shell.FlyoutBehavior="Disabled">
    
        <ShellContent
            Title="Home"
            ContentTemplate="{DataTemplate local:MainView}"
            Route="MainPage" />
    </Shell>
    

    XAML コードは、ポップアップ動作を無効にするクラスをAppShell定義し、メインコンテンツを、 クラスをShellContent指すタイトルHomeとコンテンツ テンプレートを持つ要素にMainView設定します。

  2. Visual Studio の [ソリューション エクスプローラー] ペインで、[AppShell.xaml] ファイルを展開して、分離コード ファイル [AppShell.xaml.cs] を表示します。 [AppShell.xaml.cs] を開き、ファイルの内容を次のコードで置き換えます。

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    using SignInMaui.Views;
    
    namespace SignInMaui;
    
    public partial class AppShell : Shell
    {
        public AppShell()
        {
            InitializeComponent();
            Routing.RegisterRoute("mainview", typeof(MainView));
            Routing.RegisterRoute("claimsview", typeof(ClaimsView));
        }
    }
    

    AppShell.xaml.cs ファイルを更新して、MainViewClaimsView に必要なルート登録を含めます。 InitializeComponent() メソッドを呼び出すことで、AppShell クラスの初期化が確実に行われるようにします。 RegisterRoute() メソッドは、mainviewclaimsview ルートをそれぞれのビューの種類 MainViewClaimsView に関連付けます。

プラットフォーム固有のコードを追加する

.NET MAUI アプリ プロジェクトには Platforms フォルダーが含まれており、各子フォルダーは、.NET MAUI がターゲットにできるプラットフォームを表しています。 既定のアプリケーション クラスを補完する Android アプリケーション固有の動作を提供するには、次の手順に従います。

  1. [ソリューション エクスプローラー] ペインで Platforms/Android/AndroidManifest.xml ファイルをダブルクリックして、XML エディターを開きます。 次のプロパティを更新します。

    • [アプリケーション名]MAUI CIAM に設定します。
    • [パッケージ名]SignInMaui.Droid に設定します。
    • [Android の最小バージョン] を "Android 5.0 (API レベル 21)" に設定します。
  2. [ソリューション エクスプローラー] ペインで Platforms/Android/MainActivity.cs ファイルをダブルクリックして、CSharp エディターを開きます。 ファイルの内容を次のコードで置き換えます。

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using SignInMaui.MSALClient;
    using Microsoft.Identity.Client;
    
    namespace SignInMaui;
    
    [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
    public class MainActivity : MauiAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            // configure platform specific params
            PlatformConfig.Instance.RedirectUri = $"msal{PublicClientSingleton.Instance.MSALClientHelper.AzureAdConfig.ClientId}://auth";
            PlatformConfig.Instance.ParentWindow = this;
    
            // Initialize MSAL and platformConfig is set
            _ = Task.Run(async () => await PublicClientSingleton.Instance.MSALClientHelper.InitializePublicClientAppAsync()).Result;
        }
    
        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);
            AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
        }
    }
    

    以下で追加したコードの主要な部分を理解しましょう。

    • 必要な using ステートメントが先頭に含まれています。
    • MainActivity クラスは MauiAppCompatActivity を継承して定義されていて、これは .NET MAUI の Android プラットフォームの基本クラスです。
    • [Activity] 属性が MainActivity クラスに適用され、Android アクティビティのさまざまな設定を指定しています。
      • Theme = "@style/Maui.SplashTheme" は、アクティビティのスプラッシュ テーマを設定します。
      • MainLauncher = true は、このアクティビティをアプリケーションのメイン エントリ ポイントとして指定します。
      • ConfigurationChanges はアクティビティが処理できる構成変更 ("画面サイズ"、"向き"、"UI モード"、"画面レイアウト"、"最小画面サイズ"、"密度" など) を指定します。
    • OnCreate メソッドは、アクティビティの作成時にカスタム ロジックを提供するためにオーバーライドされます。
      • base.OnCreate(savedInstanceState) は、メソッドの基本実装を呼び出します。
      • PlatformConfig.Instance.RedirectUri は、PublicClientSingleton.Instance.MSALClientHelper.AzureAdConfig.ClientId に基づいて動的に生成される値に設定されます。 MSAL クライアントのリダイレクト URI を構成します。
      • PlatformConfig.Instance.ParentWindow は、認証関連の操作の親ウィンドウを指定する現在のアクティビティ インスタンスに設定されます。
      • PublicClientSingleton.Instance.MSALClientHelper.InitializePublicClientAppAsync() は、MSALClientHelper という名前のシングルトン インスタンスのヘルパー メソッドを使用して、MSAL クライアント アプリを非同期的に初期化します。 Task.Run は、バックグラウンド スレッドで初期化を実行するために使用され、.Result はタスクが完了するまで同期的に待機するために使用されます。
    • OnActivityResult メソッドは、現在のアクティビティによって起動されたアクティビティの結果を処理するためにオーバーライドされます。
      • base.OnActivityResult(requestCode, resultCode, data) は、メソッドの基本実装を呼び出します。
      • AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data) は、受信した要求コード、結果コード、および意図データに基づいて認証継続イベント引数を設定します。 これは、外部アクティビティが結果を返した後に認証フローを続行するために使用されます。
  3. Visual Studio の [ソリューション エクスプローラー] ペインで、[プラットフォーム] を選択します。

  4. [Android] フォルダーで右クリック>[追加]>[新しい項目...]

  5. [C# 項目]>[クラス] を選択します。 そのファイルに MsalActivity.cs という名前を付けます。

  6. MsalActivity.cs ファイルの内容を次のコードで置き換えます。

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using Android.App;
    using Android.Content;
    using Android.OS;
    using Android.Runtime;
    using Android.Views;
    using Android.Widget;
    using Microsoft.Identity.Client;
    
    namespace MauiAppBasic.Platforms.Android.Resources
    {
        [Activity(Exported =true)]
        [IntentFilter(new[] { Intent.ActionView },
            Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault },
            DataHost = "auth",
            DataScheme = "msalEnter_the_Application_Id_Here")]
        public class MsalActivity : BrowserTabActivity
        {
        }
    }
    

    以下で追加したコードの主要な部分を理解しましょう。

    • MsalActivity クラスは MauiAppBasic.Platforms.Android.Resources 名前空間内で宣言されています。 このクラスは BrowserTabActivity クラスを継承しているので、その機能を拡張しています。
    • このクラスは [Activity(Exported = true)] 属性で修飾されます。これは、アクティビティがエクスポートされ、他のメソッドからアクセスできることを示します。
    • 意図フィルターは、"[IntentFilter(...)]" 属性を使用して指定します。 ActionView 意図をインターセプトするようにアクティビティを構成します。
    • 意図フィルターは、指定された DataScheme (msalEnter_the_Application_Id_Here) と DataHost ("auth") を使用して ActionView 意図を処理するように設定されます。 この構成により、アクティビティは ActionView 意図をインターセプトして処理することで、認証プロセスを処理できます。 Enter_the_Application_Id_Here を、前に登録したアプリのアプリケーション (クライアント) ID で置き換えます。

アプリ設定を追加する

設定を使用すると、アプリの動作を構成するデータをコードから分離できるため、アプリを再構築せずに動作を変更できます。 MauiAppBuilder は、.NET MAUI アプリで設定を構成するための ConfigurationManager を提供します。 appsettings.json ファイルを EmbeddedResource として追加しましょう。

appsettings.json を作成するには、次の手順に従います。

  1. Visual Studio の [ソリューション エクスプローラー] ペインで、[SignInMaui] プロジェクトで右クリック>[追加]>[新しい項目...]

  2. [Web]>[JavaScript JSON 構成ファイル] を選択します。 そのファイルに appsettings.json という名前を付けます。

  3. [追加] を選択します。

  4. [appsettings.json] を選択します

  5. [プロパティ] ペインで、[ビルド アクション][埋め込みリソース] に設定します。

  6. [プロパティ] ペインで、[出力ディレクトリにコピー][常にコピー] に設定します。

  7. appsettings.json ファイルの内容を次のコードで置き換えます。

    {
      "AzureAd": {
        "Authority": "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/",
        "ClientId": "Enter_the_Application_Id_Here",
        "CacheFileName": "msal_cache.txt",
        "CacheDir": "C:/temp"
      },
      "DownstreamApi": {
        "Scopes": "openid offline_access"
      }
    }
    
  8. appsettings.json 内で次のプレースホルダーを見つけます。

    1. Enter_the_Tenant_Subdomain_Here を、ディレクトリ (テナント) サブドメインに置き換えます。 たとえば、テナントのプライマリ ドメインが contoso.onmicrosoft.com の場合は、contoso を使用します。 テナント名がない場合は、テナントの詳細を読み取る方法を確認してください。
    2. Enter_the_Application_Id_Here を、前に登録したアプリのアプリケーション (クライアント) ID に置き換えます。

.NET MAUI モバイル アプリを実行してテストする

.NET MAUI アプリは、複数のオペレーティング システムとデバイス上で実行できるように設計されています。 どのターゲットでアプリをテストしてデバッグしたいかを選択する必要があります。

Visual Studio ツール バーの [デバッグ ターゲット] を、デバッグしてテストしたいデバイスに設定します。 次の手順は、[デバッグ ターゲット]Android に設定する方法を示しています。

  1. [デバッグ ターゲット] ドロップダウン リストを選択します。
  2. [Android エミュレーター] を選択します。
  3. エミュレーター デバイスを選択します。

F5 キーを押すか、Visual Studio の上部にある "再生ボタン" を選択してアプリを実行します。

  1. これでサンプルの .NET MAUI Android アプリをテストできるようになりました。 アプリを実行すると、エミュレーターに Android アプリ ウィンドウが表示されます。

    Android アプリケーションの [サインイン] ボタンのスクリーンショット

  2. 表示された Android ウィンドウで、[サインイン] ボタンを選択します。 ブラウザー ウィンドウが開き、サインインが求められます。

    Android アプリケーションで資格情報を入力するためのユーザー プロンプトのスクリーンショット。

    サインイン プロセス中に、さまざまなアクセス許可を付与するように求められます (アプリケーションがデータにアクセスできるようにします)。 サインインと同意が成功すると、アプリケーション画面にメイン ページが表示されます。

    サインインした後に表示される Android アプリケーションのメイン ページのスクリーンショット。

関連項目