はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

Azure AD B2Cでユーザ認証するアプリをMAUIで作ろう

AIを使ったアプリケーションを作る場合、「誰が使ったか分かるようにしてほしい」というのが要件として依頼される場合があります。
Windowsアプリに限らず、自分たちでユーザ管理部分まで作ろうと思うと、本来注力したいAI活用部分だけではなく、ユーザ管理用の仕組み、データベースなどの付随的なサーバやその管理までも発生します。
そのような、あえて言うのであれば本質ではない部分は他に任せたいとしたときの選択は次の2つです。

  1. その部分をつくってくれる人/会社に依頼する
  2. Azure AD B2Cを活用する

今回は「Azure AD B2C」を活用する方法を紹介します。
更に、Webアプリよりも「どこを作るのか」、「どう動くのか」が分かりやすいWindowsアプリとして作成する方法を紹介します。

Azure AD B2Cとは?

Azure Active Directory B2C(Azure AD B2C)は、Microsoftが提供するクラウドベースのアイデンティティ管理サービスです。これにより、企業や開発者は自社のアプリケーションに対して、安全でスケーラブルなユーザー認証を簡単に実装できます。Azure AD B2Cは、ユーザーがGoogleFacebookMicrosoftアカウントなどの既存のソーシャルアカウントを使用してサインインできるようにするほか、独自のローカルアカウントもサポートします。

このサービスは、ユーザーの登録、サインイン、パスワードリセットなどの機能を提供し、カスタマイズ可能なユーザーエクスペリエンスを実現します。また、セキュリティとコンプライアンスの要件を満たすための高度な機能も備えています。Azure AD B2Cを利用することで、開発者は認証機能の実装にかかる時間と労力を大幅に削減し、アプリケーションの開発に集中することができます。

Azure AD B2Cの説明について

上記の説明はMicrosoft Copilotに以下のプロンプトを投げて作成したものを微調整して掲載しました。

あなたは技術ブログの執筆者です。
今回は、AI活用アプリにAzure AD B2Cを使ってユーザ認証を行うための情報をブログに記載します。
そのイントロダクションとして「Azure AD B2Cとは?」というタイトルでAzure AD B2Cという名称を始めて聞く人にもわかるように500文字以内(短ければ短いほど良い)で文章を作成してください。なお、冒頭で必ずAzure AD B2Cの正式製品名を入れてください。

Azure AD B2Cの設定

Azureポータルサイトに入り、ActiveDirectory B2Cサービスにアプリを登録します。
今回は、新たに「Azure AD B2C」のリソースをつくるのではなく、Azureポータルに入っているリソース上にアプリを登録することにします。

Azure AD B2Cのリソースを分けると何ができる?

今回は、Azure AD B2Cのリソースを新規に作成しませんが、Azure AD B2Cはリソースを分けることで「Azure AD B2C テナント」が作成できます。
テナントが分かれていると組織名や初期ドメイン名を別にすることが出来ます。

また、アプリ登録やユーザ管理なども別になります。
次のようなときは、Azure AD B2Cの新規リソースを作成しましょう。

  • 同じサブスクリプションで別のアプリを登録したいとき
  • 同じアプリでもユーザ管理を別にしたいとき

おすすめとしては、アプリ開発・検証用としては、今回のようにリソースを新規作成せず、本稼働用には新しいリソースでという住み分けです。
こうすることで、重要な認証周りで、開発・検証用と本稼働用が混ざることを防止できます。

AD B2Cにアプリを登録

「リソースの追加」ではなく画面上部の検索ボックスで「Azure AD B2C」として検索し、すでにある「Azure AD B2C」リソースの機能の概要にはいります。

アプリの登録

左側のメニューから[アプリの登録]を押して、画面が変わったらメイン画面の上部メニューの「新規登録」を押します。

画面が変わったら、「表示名」、「アカウントの種類」、「リダイレクトURI」を指定します。

  • 表示名:あとから変更できるので「(検証)Azure AD B2C」と仮設定
  • アカウントの種類:「任意の組織ディレクトリ内のアカウント」を選択
  • リダイレクトURI:「パブリック クライアント/ネイティブ(モバイルとデスクトップ)」を選択(URLはあとで決めるので未記入)


準備ができたら[登録]をクリックします。

アカウントの種類とは?

今回、「任意の組織ディレクトリ内のアカウント (任意の Microsoft Entra ID テナント - マルチテナント) と個人用の Microsoft アカウント (SkypeXbox など)」を選択しました。
この選択で、企業向けアカウントと個人向けアカウントの2種類のアカウントで認証できるようになります。

  • 自社内だけということであれば、会社のディレクトリを選択してからAD B2Cにアプリ登録して、「この組織ディレクトリ内のアカウント」とします。
  • 企業向けアカウントのみにしたいということであれば、「任意の組織ディレクトリ内のアカウント (任意の Microsoft Entra ID テナント - マルチテナント)」とします。
  • 特定の企業向けにしたいときは、残念ながらAzure AD B2Cではできません。特定の企業向けにしたいときは「Microsoft Entra External ID」にアプリを登録し、お客様ドメインのみを許可するように設定します。
プラットフォームの追加

AD B2Cでは認証後のアクセストークンの返し方など、プラットフォーム固有の設定が可能です。
[管理]-[認証]メニューをクリックし、「プラットフォームの追加」を選択します。

プラットフォームの選択

今回は「モバイルアプリケーションとデスクトップアプリケーション」を選びます。

リダイレクトURIの設定

リダイレクトURIは、認証が通ったときのトークンの返却先になります。
以前は、3番目を選択すればよかったのですが、Windowsクライアントの場合は、「カスタムリダイレクトURI」として必ず「http://localhost」を指定します。

これでAzure AD B2C側の設定は完了です。

(参考)Webアプリの時のリダイレクトURIの設定

なお、「Webアプリ」を選ぶと、リダイレクトURI、ログアウトURI、アクセストークンにするのかIDトークンにするのかが選択できます。

アプリ作成

.NET MAUIアプリを「MAUIAuthApp」という名前で新規作成します。
新規作成直後に「Windows Machine」ターゲットとしてを「F5」キーを押してデバック実行すると次のような画面が表示できます。

今回は、この「Click Me」のところでAzure AD B2Cを使ってみましょう。

MVVM化

まずはテンプレートから生成されたアプリをMVVM化します。

フォルダ構成の変更

MVVMで作成するので「Models」「ViewModels」「Views」フォルダを作成して「MainPage.xaml」を「Views」フォルダの中に移動します。

MainViewModelの作成

MainPage.xamlとMainPage.xaml.csに入っていたボタン表示とボタンクリック時の動作をMainViewModelに転記します。
gist.github.com

MainPage.xaml.csの書き換え

MVVM化してカウントアップのロジックをViewから切り離したので、MainPage.xaml.csもかなりシンプルになりました。
gist.github.com

あとは、MainPage.xamlもBinding中心の記述に変更します。
gist.github.com

Azure AD B2C対応

nuget追加

次の2つを追加します。

  1. Microsoft.Identity.Client:認証処理用ライブラリ
  2. System.IdentityModel.Tokens.Jwt:トークン解析用ライブラリ


MSALを呼び出す部分の作成

まずは、MSALを呼び出す部分を作成します。
ここで混乱しやすいのは、WithRedirectUriで指定する値です。
以前であれば、ここに「msal~CliendId~://auth」の文字列を指定できていたのですが、今は「http://localhost」のみが指定できます。
gist.github.com

  1. AuthenticationServiceコンストラクタで、Azure側に登録されているアプリ情報を設定します。"common”と指定しているのは「EntraID」+「個人用MicrosoftAccount」が対象だからです。
  2. LoginAsyncのなかは、GetAccountsAsyncメソッドで既に認証されているアカウントがあれば、そのトークンを返却しようと試みています。
  3. 認証されているアカウントがなければMsalExceptionが発生するので、AcquireTokenInteractiveAsyncメソッドを呼び出します。
  4. AcquireTokenInteractiveAsyncメソッドの中では、AcquireTokenInteractiveを使って、ブラウザを自動立ち上げしてサインイン用の画面を表示します。この画面もEntraIDまたは個人用MicrosoftAccountのサインイン画面であり、今回のアプリ側の画面ではありません。
AutenticationModelの作成

AuthenticationServiceクラスができあがったので、それを呼び出すモデルを作成します。
gist.github.com
あとは、このモデルをMainViewModelのボタンクリックのところから呼び出すようにします。

private Models.AuthenticationModel Model { get; } = new Models.AuthenticationModel();

this.Message = await Model.LoginAsync();

実際の動作について

アプリが完成したので起動して「Click Me」ボタンをクリックします。
自動的にブラウザが開いて、次のようなサインイン画面がでます。

アカウント種別ごとの動きの違い

ここで初回サインインするときに、アカウント種別ごとに動作が異なりますので、分けて説明します。

EntraIDの場合

EntraIDでサインインするときに、AzureADの管理権限がない利用者の場合、次のような画面になります。

管理権限がある場合は、最初の1回だけ次のような画面になります。
[承諾]ボタンをクリックすれば、以降は、管理者権限がない人も含めて、サインインが可能になります。

個人用MicrosoftAccoutの場合

初回だけアプリの利用の同意画面がでてくるので、[同意]ボタンをクリックして先に進みます。

サインインが完了すると

outlook.jpのメルアドもっているときに、メルアドと(outlook.jpの)パスワードを入力するとブラウザには次のように表示されます。

Authentication complete. You can return to the application. Feel free to close this browser tab.

そして同時にアプリ側ではアクセストークンが取得でき、中身にはClientIdなどが含まれていて認可情報がアプリで取得できます。

AD B2Cの場合、audはClientIdと同じ値となります。
また、v1 エンドポイントにはあった「unique_name」はv2 エンドポイントにはないため、ユーザを特定するのであれば、「preferred_username」を参照してください。

以上で、Azure AD B2Cでユーザ認証をするアプリの作り方を終わります。

最後に

アプリの使用の保存場所

今回は個人用MicrosoftAccountでサインインしたので、Microsoft Accountサイトのアプリのところに今回のアプリが登録されています。「共有を停止」とすることで、アプリを使用できなくなります。

IDとパスワードの保存場所

今回のようにAzure ADB2Cでユーザ認証した場合、ユーザIDやパスワードはAD B2Cにアプリを登録したところには一切保存されていない点に注意してください。
ユーザIDやパスワードは、利用者が選択したEntraIDまたは個人用MicrosoftAccountを管理している側(つまり今回でいえばEntraIDなら自社のAzureAD)ということになります。

EntraIDでの初回サインインについて

特にEntraIDを使ったサインインについては、その企業で最初にサインインする人は、AzureADの管理者権限がある人にサインインしてもらう必要があり、勝手に自社で使われていたのようなことも防止できるような仕組みになっています。