Gestione account Web

Questo articolo descrive come usare AccountsSettingsPane per connettere l'app Universal Windows Platform (UWP) a provider di identità esterni, ad esempio Microsoft o Facebook, tramite le API di Gestione account Web di Windows 10 e Windows 11. Si apprenderà come richiedere l'autorizzazione a un utente per usare il suo account Microsoft e come ottenere un token di accesso da usare per eseguire operazioni di base, ad esempio ottenere i dati del profilo o caricare file sull'account OneDrive). I passaggi sono simili per ottenere l'autorizzazione utente e l'accesso con qualsiasi provider di identità che supporta Gestione account Web.

Nota

Per un esempio di codice completo, vedere l'esempio di WebAccountManagement in GitHub.

Effettuare la configurazione

In primo luogo, creare un'app nuova e vuota in Visual Studio.

In secondo luogo, per connettersi ai provider di identità, dovrai associare la tua app allo Store. A tale scopo, fare clic con il pulsante destro del mouse sul progetto, selezionare Store/Publish>Associa app allo Store e seguire le istruzioni della procedura guidata.

In terzo luogo, creare un'interfaccia utente molto semplice costituita da un semplice pulsante XAML e due caselle di testo.

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
	<Button x:Name="LoginButton" Content="Log in" Click="LoginButton_Click" />
	<TextBlock x:Name="UserIdTextBlock"/>
	<TextBlock x:Name="UserNameTextBlock"/>
</StackPanel>

E un gestore eventi collegato al pulsante nel code-behind:

private void LoginButton_Click(object sender, RoutedEventArgs e)
{	
}

Infine, aggiungere gli spazi dei nomi seguenti in modo da non doversi preoccupare di eventuali problemi di riferimento in un secondo momento:

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;

Visualizzare il riquadro delle impostazioni degli account

Il sistema fornisce un'interfaccia utente predefinita per la gestione di provider di identità e account Web denominati AccountsSettingsPane. È possibile mostrarlo in questo modo:

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

Se si esegue l'app e si fa clic sul pulsante "Accedi", verrà visualizzata una finestra vuota.

Screenshot of the Choose an account window with no accounts listed.

Il riquadro è vuoto perché il sistema fornisce solo una shell dell'interfaccia utente. Spetta allo sviluppatore popolare a livello di codice il riquadro con i provider di identità.

Suggerimento

Facoltativamente, è possibile usare ShowAddAccountAsync instead of Show, che restituirà un oggetto IAsyncAction, per eseguire una query sullo stato dell'operazione.

Registrarsi per AccountCommandsRequested

Per aggiungere comandi al riquadro, si inizia registrando per il gestore eventi AccountCommandsRequested. Questo indica al sistema di eseguire la logica di compilazione quando l'utente chiede di visualizzare il riquadro (ad esempio, fa clic sul pulsante XAML).

Nel code-behind eseguire l'override degli eventi OnNavigatedTo e OnNavigatedFrom e aggiungervi il codice seguente:

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

Gli utenti non interagiscono con gli account molto spesso, quindi la registrazione e la deregistrazione del gestore eventi in questo modo consentono di evitare perdite di memoria. In questo modo, il riquadro personalizzato è in memoria solo quando si verifica un'elevata probabilità che un utente lo richieda (perché si trova in una pagina "impostazioni" o "account di accesso", ad esempio).

Compilare il riquadro delle impostazioni dell'account

Il metodo BuildPaneAsync viene chiamato ogni volta che viene visualizzato AccountsSettingsPane. Qui verrà inserito il codice per personalizzare i comandi visualizzati nel riquadro.

Iniziare ottenendo un differimento. Questo indica al sistema di ritardare la visualizzazione di AccountsSettingsPane fino al termine della compilazione.

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

Ottenere quindi un provider usando il metodo WebAuthenticationCoreManager.FindAccountProviderAsync. L'URL per il provider varia in base al provider ed è disponibile nella documentazione del provider. Per gli account Microsoft e 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(); 
}

Si noti che si passa anche la stringa "consumer" al parametro di autorità facoltativo. Ciò è dovuto al fatto che Microsoft fornisce due diversi tipi di autenticazione: account Microsoft (MSA) per "consumer" e Azure Active Directory (AAD) per le "organizzazioni". L'autorità "consumer" indica che si vuole l'opzione MSA. Se si sviluppa un'app aziendale, usare invece la stringa "organizzazioni".

Infine, aggiungere il provider a AccountsSettingsPane creando un nuovo WebAccountProviderCommand come questo:

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

Il metodo GetMsaToken passato al nuovo WebAccountProviderCommand non esiste ancora (verrà compilato nel passaggio successivo), quindi è possibile aggiungerlo come metodo vuoto per il momento.

Eseguire il codice precedente e il riquadro dovrebbe essere simile al seguente:

Screenshot of the Choose an account window with accounts listed.

Richiedere un token

Dopo aver visualizzato l'opzione Account Microsoft in AccountSettingsPane, è necessario gestire cosa accade quando l'utente lo seleziona. Il metodo GetMsaToken è stato registrato per l'avvio quando l'utente sceglie di accedere con il proprio account Microsoft, quindi si otterrà il token.

Per ottenere un token, usare il metodo RequestTokenAsync come segue:

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

In questo esempio la stringa "wl.basic" viene passata al parametro scope . L'ambito rappresenta il tipo di informazioni richieste dal servizio di fornitura su un utente specifico. Alcuni ambiti forniscono l'accesso solo alle informazioni di base di un utente, ad esempio il nome e l'indirizzo di posta elettronica, mentre altri ambiti possono concedere l'accesso a informazioni riservate, ad esempio le foto o la posta in arrivo dell'utente. In genere, l'app deve usare l'ambito meno permissivo necessario per ottenere la funzione. I provider di servizi forniranno la documentazione sugli ambiti necessari per ottenere i token da usare con i servizi.

Suggerimento

Facoltativamente, se l'app usa un hint di accesso (per compilare il campo utente con un indirizzo di posta elettronica predefinito) o altre proprietà speciali correlate all'esperienza di accesso, elencarla nella proprietà WebTokenRequest.AppProperties. In questo modo il sistema ignorerà la proprietà durante la memorizzazione nella cache dell'account Web, che impedisce la mancata corrispondenza dell'account nella cache.

Se si sviluppa un'app aziendale, è probabile che si voglia connettersi a un'istanza di Azure Active Directory (AAD) e usare l'API Microsoft Graph anziché i normali servizi MSA. In questo scenario usare invece il codice seguente:

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

Il resto di questo articolo continua a descrivere lo scenario MSA, ma il codice per AAD è molto simile. Per altre informazioni su AAD/Graph, incluso un esempio completo su GitHub, vedere la documentazione di Microsoft Graph.

Uso del token

Il metodo RequestTokenAsync restituisce un oggetto WebTokenRequestResult che contiene i risultati della richiesta. Se la richiesta ha esito positivo, conterrà un token.

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

Nota

Se viene visualizzato un errore durante la richiesta di un token, assicurarsi di aver associato l'app allo Store come descritto nel passaggio uno. L'app non sarà in grado di ottenere un token se è stato ignorato questo passaggio.

Dopo aver ottenuto un token, è possibile usarlo per chiamare l'API del provider. Nel codice seguente chiameremo l'API Microsoft Live info utente per ottenere informazioni di base sull'utente e visualizzarla nell'interfaccia utente. Si noti tuttavia che nella maggior parte dei casi è consigliabile archiviare il token una volta ottenuto e quindi usarlo in un metodo separato.

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

La modalità di chiamata di varie API REST varia tra i provider; per informazioni su come usare il token, vedere la documentazione dell'API del provider.

Archiviare l'account per un uso futuro

I token sono utili per ottenere immediatamente informazioni su un utente, ma in genere hanno durata variabile: i token MSA, ad esempio, sono validi solo per alcune ore. Fortunatamente, non è necessario visualizzare nuovamente AccountsSettingsPane ogni volta che scade un token. Una volta che un utente ha autorizzato l'app, è possibile archiviare le informazioni sull'account dell'utente per un uso futuro.

A tale scopo, usare la classe WebAccount. Un WebAccount viene restituito dallo stesso metodo usato per richiedere il token:

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

Dopo aver creato un'istanza di WebAccount , è possibile archiviarla facilmente. Nell'esempio seguente viene usato LocalSettings. Per altre informazioni sull'uso di Local Impostazioni e altri metodi per archiviare i dati utente, vedere Archiviare e recuperare le impostazioni e i dati dell'app.

private async void StoreWebAccount(WebAccount account)
{
	ApplicationData.Current.LocalSettings.Values["CurrentUserProviderId"] = account.WebAccountProvider.Id;
	ApplicationData.Current.LocalSettings.Values["CurrentUserId"] = account.Id; 
}

È quindi possibile usare un metodo asincrono come il seguente per tentare di ottenere un token in background con l'account Web archiviato.

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

Posizionare il metodo precedente subito prima del codice che compila AccountsSettingsPane. Se il token viene ottenuto in background, non è necessario visualizzare il riquadro.

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

Poiché l'acquisizione di un token in modo invisibile all'utente è molto semplice, è consigliabile usare questo processo per aggiornare il token tra le sessioni anziché memorizzare nella cache un token esistente (poiché tale token potrebbe scadere in qualsiasi momento).

Nota

L'esempio precedente illustra solo i casi di esito positivo e negativo di base. L'app deve anche tenere conto di scenari insoliti (ad esempio un utente che revoca l'autorizzazione dell'app o rimuove il proprio account da Windows, ad esempio) e gestirli normalmente.

Rimuovere un account archiviato

Se si salva in modo permanente un account Web, è possibile concedere agli utenti la possibilità di annullare l'associazione del proprio account con l'app. In questo modo, possono "disconnettersi" efficacemente dall'app: le informazioni sull'account non verranno più caricate automaticamente all'avvio. A tale scopo, rimuovere prima di tutto le informazioni sull'account e sul provider salvate dalla risorsa di archiviazione. Richiamare quindi SignOutAsync per cancellare la cache e invalidare eventuali token esistenti che potrebbero essere presenti nell'app.

private async Task SignOutAccountAsync(WebAccount account)
{
	ApplicationData.Current.LocalSettings.Values.Remove("CurrentUserProviderId");
	ApplicationData.Current.LocalSettings.Values.Remove("CurrentUserId"); 
	account.SignOutAsync(); 
}

Aggiungere provider che non supportano WebAccountManager

Se si vuole integrare l'autenticazione da un servizio nell'app, ma tale servizio non supporta WebAccountManager, ad esempio Google+ o Twitter, è comunque possibile aggiungere manualmente tale provider agli AccountsSettingsPane. A tale scopo, creare un nuovo oggetto WebAccountProvider e specificare il proprio nome e .png icona, quindi aggiungerlo all'elenco WebAccountProviderCommands. Ecco del codice stub:

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
}

Nota

In questo caso viene aggiunta solo un'icona a AccountsSettingsPane e viene eseguito il metodo specificato quando si fa clic sull'icona (GetTwitterTokenAsync, in questo caso). È necessario fornire il codice che gestisce l'autenticazione effettiva. Per altre informazioni, vedere Gestore di autenticazione Web, che fornisce metodi helper per l'autenticazione tramite i servizi REST.

Aggiungere un'intestazione personalizzata

È possibile personalizzare il riquadro delle impostazioni dell'account usando la proprietà HeaderText, come illustrato di seguito:

private async void BuildPaneAsync(AccountsSettingsPane s, AccountsSettingsPaneCommandsRequestedEventArgs e)
{
	// other code here 
	
	args.HeaderText = "MyAwesomeApp works best if you're signed in."; 	
	
	// other code here
}

Screenshot of the Choose an account window with no accounts listed and a message that says My Awesome App works best if you're signed in.

Non andare a bordo con il testo dell'intestazione; tenerlo breve e dolce. Se il processo di accesso è complicato ed è necessario visualizzare altre informazioni, collegare l'utente a una pagina separata usando un collegamento personalizzato.

È possibile aggiungere comandi personalizzati a AccountsSettingsPane, che vengono visualizzati come collegamenti sotto i WebAccountProvider supportati. I comandi personalizzati sono ideali per attività semplici correlate agli account utente, ad esempio la visualizzazione di un'informativa sulla privacy o l'avvio di una pagina di supporto per gli utenti che hanno problemi.

Ecco un esempio:

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
}

Screenshot of the Choose an account window with no accounts listed and a link to a Privacy policy.

Teoricamente, è possibile usare i comandi delle impostazioni per qualsiasi elemento. È tuttavia consigliabile limitare l'uso a scenari intuitivi correlati all'account, come quelli descritti in precedenza.

Vedi anche

Windows.Security.Authentication.Web.Core namespace

Spazio dei nomi Windows.Security.Credentials

AccountsSettingsPane class

Gestore di autenticazioni Web

Esempio di gestione degli account Web

App di pianificazione Lunch