共用方式為


Web 帳戶管理員

本文說明如何使用 AccountsSettingsPane ,使用 Windows Web 帳戶管理員 API 將通用 Windows 平臺 (UWP) 應用程式連線到外部身分識別提供者,例如Microsoft或 Facebook。 您將了解如何要求使用者使用其 Microsoft 帳戶的權限、取得存取權杖,以及使用它執行基本作業 (例如取得設定檔資料或將檔案上傳到其 OneDrive 帳戶)。 這些步驟與透過支援 Web 帳戶管理員的身分識別提供者取得使用者權限和存取權類似。

注意

如需完整的程式碼範例,請參閱 GitHub 上的 WebAccountManagement 範例

開始設定

首先,在Visual Studio中建立新的空白UWP應用程式。

其次,若要連接到身分識別提供者,您需要將應用程式與商店關聯。 若要這樣做,請以滑鼠右鍵按一下您的專案,選擇 Store/Publish>Associate 應用程式與商店,然後按照精靈的說明進行操作。

第三,建立一個非常基本的 UI,其中包含一個簡單的 XAML 按鈕和兩個文字方塊。

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
	<Button x:Name="SignInButton" Content="Sign in" Click="SignInButton_Click" />
	<TextBlock x:Name="UserIdTextBlock"/>
	<TextBlock x:Name="UserNameTextBlock"/>
</StackPanel>

並在程式碼後置中附加到按鈕的事件處理常式:

private void SignInButton_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;

顯示帳戶設定窗格

系統提供了一個名為 AccountsSettingsPane 的內建使用者介面,用於管理身分識別提供者和 Web 帳戶。 您可以將其顯示如下:

private void SignInButton_Click(object sender, RoutedEventArgs e)
{
	AccountsSettingsPane.Show(); 
}

如果您執行應用程式並按兩下 [登入] 按鈕,它應該會顯示空白視窗。

[選擇帳戶] 視窗的螢幕快照,其中未列出任何帳戶。

窗格是空的,因為系統只提供UI殼層, 開發人員必須以程式設計方式填入窗格與識別提供者。

提示

您可以選擇性地使用 ShowAddAccountAsync ,而不是 Show,這會傳回 IAsyncAction 來查詢作業的狀態。

註冊 AccountCommandsRequested

若要將命令新增至窗格,我們從註冊 AccountCommandsRequested 事件處理程序開始。 這會告訴系統在使用者要求查看窗格時,執行我們的建置邏輯 (例如,按一下我們的 XAML 按鈕)。

在程式碼後台中,覆寫 OnNavigatedToOnNavigatedFrom 事件,並將以下程式碼新增至其中:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
	AccountsSettingsPane.GetForCurrentView().AccountCommandsRequested += BuildPaneAsync; 
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
	AccountsSettingsPane.GetForCurrentView().AccountCommandsRequested -= BuildPaneAsync; 
}

使用者不會經常與帳戶互動,因此以這種方式註冊和取消註冊事件處理常式有助於防止記憶體流失。 如此一來,您的自定義窗格只會在使用者要求它時處於記憶體中(例如,因為它們位於「設定」或「登入」頁面上)。

建置帳戶設定窗格

每當顯示 AccountsSettingsPane 時,就會呼叫 BuildPaneAsync 方法。 我們將在此處放置程式碼來自訂窗格中顯示的命令。

先取得延遲。 這會告訴系統延遲顯示 AccountsSettingsPane,直到我們完成建置為止。

private async void BuildPaneAsync(AccountsSettingsPane s,
	AccountsSettingsPaneCommandsRequestedEventArgs e)
{
	var deferral = e.GetDeferral();
		
	deferral.Complete(); 
}

接下來,使用 WebAuthenticationCoreManager.FindAccountProviderAsync 方法取得提供者。 提供者的 URL 會根據提供者而有所不同,其可以在提供者的文件中找到。 若為 Microsoft Accounts 和 Microsoft Entra,則為 “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(); 
}

請注意,我們也會將字串 「consumers」 傳遞給選擇性 授權單位 參數。 這是因為Microsoft提供兩種不同類型的驗證:Microsoft帳戶(MSA)用於「消費者」,以及Microsoft Entra用於「組織」。 「消費者」授權單位表示我們需要 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(); 
}

我們傳遞至新 WebAccountProviderCommandGetMsaTokenAsync 方法尚不存在(我們將在下一個步驟中建置該方法),因此請隨意將其新增為空的方法。

執行上述程式碼,您的窗格應如下所示:

[選擇帳戶] 視窗的螢幕快照,其中列出帳戶。

要求權杖

一旦我們在 AccountsSettingsPane 中顯示了 Microsoft 帳戶選項,我們就需要處理使用者選擇它時會發生的情況。 我們已註冊GetMsaTokenAsync 方法,以便在用戶選擇使用其 Microsoft 帳戶登入的時候觸發,從而能在此處取得令牌。

若要取得令牌,請使用 RequestTokenAsync 方法,如下所示:

private async void GetMsaTokenAsync(WebAccountProviderCommand command)
{
	WebTokenRequest request = new WebTokenRequest(command.WebAccountProvider, "wl.basic");
	WebTokenRequestResult result = await WebAuthenticationCoreManager.RequestTokenAsync(request);
}

在此範例中,我們會將字串「wl.basic」傳遞給範圍參數。 範圍代表您從特定使用者的提供服務要求的資訊類型。 某些範圍僅提供對使用者基本資訊 (如姓名和電子郵件地址) 的存取權,而其他範圍可能會授予對敏感資訊 (如使用者照片或電子郵件收件匣) 的存取權。 一般來說,您的應用程式應該使用最寬鬆的範圍來實現其功能。 服務提供者將提供有關取得用於其服務之權杖所需範圍的文件。

提示

如果您的應用程式使用登入提示(以預設電子郵件位址填入使用者欄位),或與登入體驗相關的其他特殊屬性,您可以選擇性地將其列在 WebTokenRequest.AppProperties 屬性中。 這會導致系統在快取 Web 帳戶的過程中忽略該屬性,從而防止快取中的帳戶不匹配。

如果您正在開發企業應用程式,您可能會想要連線到Microsoft Entra 實例,並使用 Microsoft Graph API,而不是一般 MSA 服務。 在這種情況下,請改用以下程式碼:

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 案例,但Microsoft Entra 的程式代碼非常類似。 如需 Entra/Graph 的詳細資訊,包括 GitHub 上的完整範例,請參閱 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; 
	}
}

注意

如果您在要求權杖時收到錯誤,請確保您已按照第一步所述將您的應用程式與應用程式商店相關聯。 如果您跳過此步驟,您的應用程式將無法取得權杖。

獲得權杖後,您可以使用它來呼叫提供者的 API。 在下列程式代碼中,我們將呼叫 使用者資訊Microsoft 365 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。 一旦使用者授權您的應用程式一次,您就可以儲存使用者的帳戶資訊以供將來使用。

若要這樣做,請使用 WebAccount 類別。 透過與要求權杖相同的方法返回 WebAccount

private async void GetMsaTokenAsync(WebAccountProviderCommand command)
{
	var 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 和其他方法來儲存使用者資料的詳細資訊,請參閱 儲存和擷取應用程式設定和數據

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);

	var 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 async void SignInButton_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();
	}
}

由於以無訊息方式取得權杖非常簡單,因此您應該使用此程序在工作階段之間重新整理權杖,而不是快取現有權杖 (因為該權杖隨時可能過期)。

注意

上述範例只涵蓋了基本的成功和失敗案例。 您的應用程式還應該考慮異常情況 (例如,使用者撤銷您的應用程式的權限,或從 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 - Instagram 或 X/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 sign-in here
}

注意

這只會將圖示新增至 AccountsSettingsPane,並在按一下圖示時執行您指定的方法(在此範例中為 GetTwitterTokenAsync)。 您必須提供處理實際驗證的程式碼。 如需詳細資訊,請參閱 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
}

[選擇未列出的帳戶] 和 [隱私策略] 連結的 [選擇帳戶] 視窗螢幕快照。

理論上,您可以使用設定命令處理一切。 但是,我們建議只在如上所述,與帳戶相關的場景中使用設定命令。

Web 驗證代理人

Web 帳戶管理範例

Lunch Scheduler 應用程式