Web アカウント マネージャー
この記事では、AccountsSettingsPane を使用して、Windows 10 および Windows 11 Web アカウント マネージャー API を使用して、ユニバーサル Windows プラットフォーム (UWP) アプリを Microsoft や Facebook などの外部 ID プロバイダーに接続する方法について説明します。 Microsoft アカウントの使用、アクセス トークンの取得、基本的な操作 (プロファイル データの取得や OneDrive アカウントへのファイルのアップロードなど) の実行にユーザーのアクセス許可を要求する方法について説明します。 この手順は、Web アカウント マネージャーをサポートする任意の ID プロバイダーでユーザーのアクセス許可とアクセス権を取得する場合と同様です。
Note
完全なコード サンプルについては、GitHub の WebAccountManagement サンプルを参照してください。
準備
まず、Visual Studio で新しい空のアプリを作成します。
次に、ID プロバイダーに接続するには、アプリをストアに関連付ける必要があります。 これを行うには、プロジェクトを右クリックして、[ストア/発行]>[アプリケーションをストアと関連付ける] を選択し、ウィザードの指示に従います。
3 番目に、単純な XAML ボタンと 2 つのテキスト ボックスで構成される非常に基本的な UI を作成します。
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="LoginButton" Content="Log in" Click="LoginButton_Click" />
<TextBlock x:Name="UserIdTextBlock"/>
<TextBlock x:Name="UserNameTextBlock"/>
</StackPanel>
分離コード内のボタンにアタッチされたイベント ハンドラー:
private void LoginButton_Click(object sender, RoutedEventArgs e)
{
}
最後に、後で参照の問題を心配する必要がないように、次の名前空間を追加します。
using System;
using Windows.Security.Authentication.Web.Core;
using Windows.System;
using Windows.UI.ApplicationSettings;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Data.Json;
using Windows.UI.Xaml.Navigation;
using Windows.Web.Http;
アカウント設定ウィンドウを表示する
システムには、ID プロバイダーと AccountsSettingsPane と呼ばれる Web アカウントを管理するための組み込みのユーザー インターフェイスが用意されています。 次のように表示できます。
private void LoginButton_Click(object sender, RoutedEventArgs e)
{
AccountsSettingsPane.Show();
}
アプリを実行して [ログイン] ボタンをクリックすると、空のウィンドウが表示されます。
このウィンドウは空です。これは、システムが UI シェルのみを提供するためです。プログラムによってウィンドウに ID プロバイダーを設定するのは開発者が行う必要があります。
ヒント
必要に応じて、Show ではなく ShowAddAccountAsync を使用することで、操作の状態を照会する IAsyncAction が返されます。
AccountCommandsRequested に登録する
ウィンドウにコマンドを追加するには、まず AccountCommandsRequested イベント ハンドラーに登録します。 これにより、ユーザーがウィンドウを表示するよう求めたとき (たとえば、XAML ボタンのクリックなど) に構築したロジックをシステムが実行するようにできます。
分離コードで、OnNavigatedTo イベントと OnNavigatedFrom イベントをオーバーライドし、次のコードを追加します。
protected override void OnNavigatedTo(NavigationEventArgs e)
{
AccountsSettingsPane.GetForCurrentView().AccountCommandsRequested += BuildPaneAsync;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
AccountsSettingsPane.GetForCurrentView().AccountCommandsRequested -= BuildPaneAsync;
}
ユーザーは頻繁にアカウントを操作しないため、この方法でイベント ハンドラーを登録および登録解除すると、メモリ リークを防ぐことができます。 これにより、カスタマイズされたウィンドウは、ユーザーが要求する可能性が高い場合にのみメモリ内にあります (たとえば、"設定" または "ログイン" ページにあるため)。
[アカウント設定] ウィンドウをビルドする
BuildPaneAsync メソッドは、 AccountsSettingsPane が表示されるたびに呼び出されます。 ここでは、ウィンドウに表示されるコマンドをカスタマイズするコードを配置します。
まず、遅延を取得します。 これにより、ビルドが完了するまで、 AccountsSettingsPane の表示を遅らせるようシステムに指示します。
private async void BuildPaneAsync(AccountsSettingsPane s,
AccountsSettingsPaneCommandsRequestedEventArgs e)
{
var deferral = e.GetDeferral();
deferral.Complete();
}
次に、WebAuthenticationCoreManager.FindAccountProviderAsync メソッドを使用してプロバイダーを取得します。 プロバイダーの URL はプロバイダーによって異なり、プロバイダーのドキュメントで確認できます。 Microsoft アカウントと Azure Active Directory では、"https://login.microsoft.com"" です。
private async void BuildPaneAsync(AccountsSettingsPane s,
AccountsSettingsPaneCommandsRequestedEventArgs e)
{
var deferral = e.GetDeferral();
var msaProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync(
"https://login.microsoft.com", "consumers");
deferral.Complete();
}
また、省略可能な authority パラメーターに文字列 "consumers" も渡すことに注意してください。 これは、Microsoft が 2 種類の認証 ("コンシューマー" 用の Microsoft アカウント (MSA) と "組織" 用の Azure Active Directory (AAD) を提供しているためです。 "コンシューマー" 機関は、MSA オプションが必要であることを示します。 エンタープライズ アプリを開発している場合は、代わりに文字列 "organizations" を使用します。
最後に、次のように新しい WebAccountProviderCommand を作成して、プロバイダーを AccountsSettingsPane に追加します。
private async void BuildPaneAsync(AccountsSettingsPane s,
AccountsSettingsPaneCommandsRequestedEventArgs e)
{
var deferral = e.GetDeferral();
var msaProvider = await WebAuthenticationCoreManager.FindAccountProviderAsync(
"https://login.microsoft.com", "consumers");
var command = new WebAccountProviderCommand(msaProvider, GetMsaTokenAsync);
e.WebAccountProviderCommands.Add(command);
deferral.Complete();
}
新しい WebAccountProviderCommand に渡した GetMsaToken メソッドはまだ存在しないため (次の手順でビルドします)、空のメソッドとして追加してください。
上記のコードを実行すると、ウィンドウは次のようになります。
トークンの要求
AccountsSettingsPaneに Microsoft アカウント オプションが表示されたら、ユーザーが選択したときに何が起こるかを処理する必要があります。 ユーザーが Microsoft アカウントでログインすることを選択したときに起動するように GetMsaToken メソッドを登録したので、そこでトークンを取得します。
トークンを取得するには、次のように RequestTokenAsync メソッドを使用します。
private async void GetMsaTokenAsync(WebAccountProviderCommand command)
{
WebTokenRequest request = new WebTokenRequest(command.WebAccountProvider, "wl.basic");
WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
}
この例では、文字列 "wl.basic" を scope パラメーターに渡します。 スコープは、特定のユーザーの提供サービスから要求する情報の種類を表します。 特定のスコープでは、名前やメール アドレスなどのユーザーの基本情報にのみアクセスできます。一方、他のスコープでは、ユーザーの写真や電子メールの受信トレイなどの機密情報へのアクセスが許可される場合があります。 一般に、アプリでは、その機能を実現するために必要な最も制限の少ないスコープを使用する必要があります。 サービス プロバイダーは、サービスで使用するトークンを取得するために必要なスコープに関するドキュメントを提供します。
- Microsoft 365 および Outlook.com のスコープについては、「Outlook REST API を使用する (バージョン 2.0)」を参照してください。
- OneDrive のスコープについては、「 OneDrive 認証とサインイン」を参照してください。
ヒント
必要に応じて、アプリでログイン ヒント (既定のメール アドレスをユーザー フィールドに設定するため) またはサインイン エクスペリエンスに関連する他の特殊なプロパティを使用する場合は、WebTokenRequest.AppProperties プロパティに一覧表示されます。 これにより、システムでは Web アカウントをキャッシュするときにプロパティが無視されるため、キャッシュ内のアカウントの不一致を防ぐことができます。
エンタープライズ アプリを開発している場合は、通常の MSA サービスではなく、Azure Active Directory (AAD) インスタンスに接続し、Microsoft Graph API を使用することをお勧めします。 このシナリオでは、代わりに次のコードを使用します。
private async void GetAadTokenAsync(WebAccountProviderCommand command)
{
string clientId = "your_guid_here"; // Obtain your clientId from the Azure Portal
WebTokenRequest request = new WebTokenRequest(provider, "User.Read", clientId);
request.Properties.Add("resource", "https://graph.microsoft.com");
WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
}
この記事の残りの部分では引き続き MSA シナリオについて説明しますが、AAD のコードは非常によく似ています。 GitHub の完全なサンプルを含む AAD/Graph の詳細については、 Microsoft Graph のドキュメントを参照してください。
トークンを使用する
RequestTokenAsync メソッドは、要求の結果を含む WebTokenRequestResult オブジェクトを返します。 要求が成功した場合は、トークンが含まれます。
private async void GetMsaTokenAsync(WebAccountProviderCommand command)
{
WebTokenRequest request = new WebTokenRequest(command.WebAccountProvider, "wl.basic");
WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
if (result.ResponseStatus == WebTokenRequestStatus.Success)
{
string token = result.ResponseData[0].Token;
}
}
Note
トークンの要求時にエラーが発生した場合は、手順 1 で説明されているように、アプリがストアに関連付けられていることを確認してください。 この手順をスキップした場合、アプリはトークンを取得できません。
トークンを取得したら、それを使用してプロバイダーの API を呼び出すことができます。 次のコードでは、 ユーザー情報 Microsoft Live API を呼び出して ユーザーに関する基本情報を取得し、UI に表示します。 ただし、ほとんどの場合、取得したトークンを格納してから、別のメソッドで使用することをお勧めします。
private async void GetMsaTokenAsync(WebAccountProviderCommand command)
{
WebTokenRequest request = new WebTokenRequest(command.WebAccountProvider, "wl.basic");
WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
if (result.ResponseStatus == WebTokenRequestStatus.Success)
{
string token = result.ResponseData[0].Token;
var restApi = new Uri(@"https://apis.live.net/v5.0/me?access_token=" + token);
using (var client = new HttpClient())
{
var infoResult = await client.GetAsync(restApi);
string content = await infoResult.Content.ReadAsStringAsync();
var jsonObject = JsonObject.Parse(content);
string id = jsonObject["id"].GetString();
string name = jsonObject["name"].GetString();
UserIdTextBlock.Text = "Id: " + id;
UserNameTextBlock.Text = "Name: " + name;
}
}
}
さまざまな REST API を呼び出す方法は、プロバイダーによって異なります。トークンの使用方法については、プロバイダーの API ドキュメントを参照してください。
今後使用するためにアカウントを保存する
トークンはユーザーに関する情報をすぐに取得するのに役立ちますが、通常は有効期間が異なります。たとえば、MSA トークンは数時間のみ有効です。 さいわい、トークンの有効期限が切れるたびに、 AccountsSettingsPane を再表示する必要はありません。 ユーザーがアプリを 1 回承認したら、後で使用できるようにユーザーのアカウント情報を格納できます。
これを行うには、 WebAccount クラスを使用します。 WebAccount は、トークンの要求に使用したのと同じメソッドによって返されます。
private async void GetMsaTokenAsync(WebAccountProviderCommand command)
{
WebTokenRequest request = new WebTokenRequest(command.WebAccountProvider, "wl.basic");
WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
if (result.ResponseStatus == WebTokenRequestStatus.Success)
{
WebAccount account = result.ResponseData[0].WebAccount;
}
}
WebAccount インスタンスを作成したら、簡単に格納できます。 次の例では、LocalSettings を使用します。 LocalSettings やその他のメソッドを使用してユーザー データを格納する方法の詳細については、「 Store とアプリの設定とデータを取得するを参照してください。
private async void StoreWebAccount(WebAccount account)
{
ApplicationData.Current.LocalSettings.Values["CurrentUserProviderId"] = account.WebAccountProvider.Id;
ApplicationData.Current.LocalSettings.Values["CurrentUserId"] = account.Id;
}
その後、次のような非同期メソッドを使用して、格納された WebAccountを使用してバックグラウンドでトークンを取得できます。
private async Task<string> GetTokenSilentlyAsync()
{
string providerId = ApplicationData.Current.LocalSettings.Values["CurrentUserProviderId"]?.ToString();
string accountId = ApplicationData.Current.LocalSettings.Values["CurrentUserId"]?.ToString();
if (null == providerId || null == accountId)
{
return null;
}
WebAccountProvider provider = await WebAuthenticationCoreManager.FindAccountProviderAsync(providerId);
WebAccount account = await WebAuthenticationCoreManager.FindAccountAsync(provider, accountId);
WebTokenRequest request = new WebTokenRequest(provider, "wl.basic");
WebTokenRequestResult result = await WebAuthenticationCoreManager.GetTokenSilentlyAsync(request, account);
if (result.ResponseStatus == WebTokenRequestStatus.UserInteractionRequired)
{
// Unable to get a token silently - you'll need to show the UI
return null;
}
else if (result.ResponseStatus == WebTokenRequestStatus.Success)
{
// Success
return result.ResponseData[0].Token;
}
else
{
// Other error
return null;
}
}
上記のメソッドは、 AccountsSettingsPane をビルドするコードの直前に配置します。 トークンがバックグラウンドで取得された場合、ペインを表示する必要はありません。
private void LoginButton_Click(object sender, RoutedEventArgs e)
{
string silentToken = await GetMsaTokenSilentlyAsync();
if (silentToken != null)
{
// the token was obtained. store a reference to it or do something with it here.
}
else
{
// the token could not be obtained silently. Show the AccountsSettingsPane
AccountsSettingsPane.Show();
}
}
トークンをサイレントで取得するのは非常に簡単であるため、このプロセスを使用して、既存のトークンをキャッシュするのではなく、セッション間でトークンを更新する必要があります (そのトークンはいつでも期限切れになる可能性があるため)。
Note
上記の例では、基本的な成功と失敗のケースのみを取り上げたものです。 アプリでは、通常とは異なるシナリオ (アプリのアクセス許可を取り消すユーザーや Windows からアカウントを削除するなど) も考慮し、適切に処理する必要があります。
保存されているアカウントを削除する
Web アカウントを保持する場合は、ユーザーに自分のアカウントとアプリの関連付けを解除する機能を付与することができます。 これにより、ユーザーはアプリから効率的に "ログアウト" することができます。起動時、ユーザーのアカウント情報は自動的に読み込まれなくなります。 これを行うには、まず、保存されているアカウントとプロバイダーの情報をストレージから削除します。 次に、 SignOutAsync を呼び出してキャッシュをクリアし、アプリが持つ可能性がある既存のトークンを無効にします。
private async Task SignOutAccountAsync(WebAccount account)
{
ApplicationData.Current.LocalSettings.Values.Remove("CurrentUserProviderId");
ApplicationData.Current.LocalSettings.Values.Remove("CurrentUserId");
account.SignOutAsync();
}
WebAccountManager をサポートしていないプロバイダーを追加する
サービスからの認証をアプリに統合するが、そのサービスが WebAccountManager (Google+ や Twitter など) をサポートしていない場合でも、そのプロバイダーを AccountsSettingsPane に手動で追加できます。 これを行うには、新しい WebAccountProvider オブジェクトを作成し、独自の名前と.png アイコンを指定し、それを WebAccountProviderCommands リストに追加します。 スタブ コードを次に示します。
private async void BuildPaneAsync(AccountsSettingsPane s, AccountsSettingsPaneCommandsRequestedEventArgs e)
{
// other code here
var twitterProvider = new WebAccountProvider("twitter", "Twitter", new Uri(@"ms-appx:///Assets/twitter-auth-icon.png"));
var twitterCmd = new WebAccountProviderCommand(twitterProvider, GetTwitterTokenAsync);
e.WebAccountProviderCommands.Add(twitterCmd);
// other code here
}
private async void GetTwitterTokenAsync(WebAccountProviderCommand command)
{
// Manually handle Twitter login here
}
Note
これにより、アイコンが AccountsSettingsPane に追加され、アイコンがクリックされたときに指定したメソッド (この場合は Get TwitterTokenAsync) が実行されます。 実際の認証を処理するコードを指定する必要があります。 詳しくは、「Web 認証ブローカー」を参照してください。REST サービスを使った認証のためのヘルパー メソッドが提供されています。
カスタム ヘッダーを追加する
次のように、HeaderText プロパティを使用してアカウント設定ウィンドウをカスタマイズできます。
private async void BuildPaneAsync(AccountsSettingsPane s, AccountsSettingsPaneCommandsRequestedEventArgs e)
{
// other code here
args.HeaderText = "MyAwesomeApp works best if you're signed in.";
// other code here
}
ヘッダー テキストをオーバーボードしないでください。短く甘く保つ。 ログイン プロセスが複雑で、詳細情報を表示する必要がある場合は、カスタム リンクを使用してユーザーを別のページにリンクします。
カスタム リンクを追加する
AccountsSettingsPane にカスタム コマンドを追加できます。これは、サポートされている WebAccountProviders の下にリンクとして表示されます。 カスタム コマンドは、ユーザー アカウントに関連する簡単なタスク (プライバシー ポリシーの表示や、問題のあるユーザー向けのサポート ページの起動など) に最適です。
次に例を示します。
private async void BuildPaneAsync(AccountsSettingsPane s, AccountsSettingsPaneCommandsRequestedEventArgs e)
{
// other code here
var settingsCmd = new SettingsCommand(
"settings_privacy",
"Privacy policy",
async (x) => await Launcher.LaunchUriAsync(new Uri(@"https://privacy.microsoft.com/en-US/")));
e.Commands.Add(settingsCmd);
// other code here
}
理論的には、何に対しても設定コマンドを使用できます。 ただし、上記のような直感的なアカウント関連のシナリオに使用を制限することをお勧めします。
関連項目
Windows.Security.Authentication.Web.Core 名前空間