Gerenciador de Contas da Web

Este artigo descreve como usar o AccountsSettingsPane para conectar seu aplicativo UWP (Plataforma Universal do Windows) a provedores de identidade externos, como Microsoft ou Facebook, usando as APIs do Gerenciador de Contas da Web do Windows 10 e do Windows 11. Você aprenderá a solicitar a permissão de um usuário para usar sua conta da Microsoft, obter um token de acesso e usá-lo para executar operações básicas (como obter dados de perfil ou carregar arquivos em sua conta do OneDrive). As etapas são semelhantes para obter permissão e acesso do usuário com qualquer provedor de identidade que ofereça suporte ao Gerenciador de contas da Web.

Observação

Para obter um exemplo de código completo, consulte o exemplo WebAccountManagement no GitHub.

Prepare-se para começar

Primeiro, crie um novo aplicativo em branco no Visual Studio.

Em segundo lugar, para se conectar a provedores de identidade, você precisará associar seu aplicativo à Loja. Para fazer isso, clique com o botão direito do mouse em seu projeto, escolha Armazenar/Publicar>Associar aplicativo à loja e siga as instruções do assistente.

Em terceiro lugar, crie uma interface do usuário muito básica que consiste em um botão XAML simples e duas caixas de texto.

<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 um manipulador de eventos anexado ao seu botão no code-behind:

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

Por fim, adicione os seguintes namespaces para que você não precise se preocupar com problemas de referência posteriormente:

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;

Mostrar o painel de configurações de contas

O sistema fornece uma interface de usuário interna para gerenciar provedores de identidade e contas da Web chamada AccountsSettingsPane. Você pode mostrar assim:

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

Se você executar seu aplicativo e clicar no botão "Login", ele deverá exibir uma janela vazia.

Captura de tela da janela Escolha uma conta sem contas listadas.

O painel está vazio porque o sistema fornece apenas um shell de interface do usuário – cabe ao desenvolvedor preencher programaticamente o painel com os provedores de identidade.

Dica

Opcionalmente, você pode usar ShowAddAccountAsync em vez de Show, que retornará um IAsyncAction, para consultar o status da operação.

Registre-se para AccountCommandsRequested

Para adicionar comandos ao painel, começamos registrando-se no manipulador de eventos AccountCommandsRequested. Isso informa ao sistema para executar nossa lógica de compilação quando o usuário pede para ver o painel (por exemplo, clica em nosso botão XAML).

No code-behind, substitua os eventos OnNavigatedTo e OnNavigatedFrom e adicione o seguinte código a eles:

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

Os usuários não interagem com contas com muita frequência, portanto, registrar e cancelar o registro do manipulador de eventos dessa maneira ajuda a evitar vazamentos de memória. Dessa forma, seu painel personalizado só fica na memória quando há uma grande chance de um usuário solicitá-lo (porque ele está em uma página de "configurações" ou "login", por exemplo).

Criar o painel de configurações da conta

O método BuildPaneAsync é chamado sempre que o AccountsSettingsPane é mostrado. É aqui que colocaremos o código para personalizar os comandos mostrados no painel.

Comece obtendo um adiamento. Isso informa ao sistema para atrasar a exibição do AccountsSettingsPane até que terminemos de criá-lo.

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

Em seguida, obtenha um provedor usando o método WebAuthenticationCoreManager.FindAccountProviderAsync. A URL do provedor varia de acordo com o provedor e pode ser encontrada na documentação do provedor. Para contas da 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(); 
}

Observe que também passamos a cadeia de caracteres "consumidores" para o parâmetro opcional authority . Isso ocorre porque a Microsoft fornece dois tipos diferentes de autenticação – MSA (Contas da Microsoft) para "consumidores" e AAD (Azure Active Directory) para "organizações". A autoridade de "consumidores" indica que queremos a opção MSA. Se você estiver desenvolvendo um aplicativo empresarial, use a cadeia de caracteres "organizações".

Por fim, adicione o provedor ao AccountsSettingsPane criando um novo WebAccountProviderCommand como este:

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

O método GetMsaToken que passamos para nosso novo WebAccountProviderCommand ainda não existe (vamos criá-lo na próxima etapa), portanto, sinta-se à vontade para adicioná-lo como um método vazio por enquanto.

Execute o código acima e seu painel deve ser semelhante a este:

Captura de tela da janela Escolha uma conta com contas listadas.

Solicitar um token

Depois que tivermos a opção Conta da Microsoft exibida no Painel de Configuraçõesde Contas, precisamos lidar com o que acontece quando o usuário a seleciona. Registramos nosso método GetMsaToken para disparar quando o usuário optar por fazer logon com sua conta da Microsoft, portanto, obteremos o token lá.

Para obter um token, use o método RequestTokenAsync da seguinte forma:

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

Neste exemplo, passamos a string "wl.basic" para o parâmetro scope . Escopo representa o tipo de informação que você está solicitando do serviço de fornecimento em um usuário específico. Determinados escopos fornecem acesso apenas às informações básicas de um usuário, como nome e endereço de email, enquanto outros escopos podem conceder acesso a informações confidenciais, como fotos do usuário ou caixa de entrada de email. Geralmente, seu aplicativo deve usar o escopo menos permissivo necessário para atingir sua função. Os provedores de serviços fornecerão documentação sobre quais escopos são necessários para obter tokens para uso com seus serviços.

Dica

Opcionalmente, se o aplicativo usar uma dica de logon (para preencher o campo de usuário com um endereço de email padrão) ou outra propriedade especial relacionada à experiência de entrada, liste-a na propriedade WebTokenRequest.AppProperties . Isso fará com que o sistema ignore a propriedade ao armazenar em cache a conta da Web, o que evita incompatibilidades de conta no cache.

Se você estiver desenvolvendo um aplicativo empresarial, provavelmente desejará se conectar a uma instância do Azure Active Directory (AAD) e usar a API do Microsoft Graph em vez de serviços MSA regulares. Nesse cenário, use o seguinte código:

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

O restante deste artigo continua descrevendo o cenário do MSA, mas o código do AAD é muito semelhante. Para obter mais informações sobre o AAD/Graph, incluindo um exemplo completo no GitHub, consulte a documentação do Microsoft Graph.

Usar o token

O método RequestTokenAsync retorna um objeto WebTokenRequestResult, que contém os resultados da solicitação. Se sua solicitação for bem-sucedida, ela conterá um 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; 
	}
}

Observação

Se você receber um erro ao solicitar um token, verifique se associou seu aplicativo à Loja, conforme descrito na etapa um. Seu aplicativo não poderá obter um token se você ignorar esta etapa.

Depois de ter um token, você pode usá-lo para chamar a API do seu provedor. No código abaixo, chamaremos as informações do usuário da API do Microsoft Live para obter informações básicas sobre o usuário e exibi-las em nossa interface do usuário. Observe, no entanto, que, na maioria dos casos, é recomendável armazenar o token uma vez obtido e usá-lo em um método separado.

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

A forma como você chama várias APIs REST varia entre os provedores; consulte a documentação da API do provedor para obter informações sobre como usar seu token.

Armazenar a conta para uso futuro

Os tokens são úteis para obter imediatamente informações sobre um usuário, mas geralmente têm vida útil variável - os tokens MSA, por exemplo, são válidos apenas por algumas horas. Felizmente, você não precisa mostrar novamente o AccountsSettingsPane sempre que um token expirar. Depois que um usuário autorizar seu aplicativo uma vez, você poderá armazenar as informações da conta do usuário para uso futuro.

Para fazer isso, use a classe WebAccount . Uma WebAccount é retornada pelo mesmo método usado para solicitar o 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; 
	}
}

Depois de ter uma instância WebAccount , você pode armazená-la facilmente. No exemplo a seguir, usamos LocalSettings. Para obter mais informações sobre como usar LocalSettings e outros métodos para armazenar dados do usuário, consulte Armazenar e recuperar configurações e dados do aplicativo.

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

Em seguida, podemos usar um método assíncrono como o seguinte para tentar obter um token em segundo plano com a WebAccount armazenada.

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

Coloque o método acima antes do código que cria o AccountsSettingsPane. Se o token for obtido em segundo plano, não há necessidade de mostrar o painel.

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

Como obter um token silenciosamente é muito simples, você deve usar esse processo para atualizar seu token entre as sessões em vez de armazenar em cache um token existente (já que esse token pode expirar a qualquer momento).

Observação

O exemplo acima abrange apenas casos básicos de sucesso e falha. Seu aplicativo também deve levar em conta cenários incomuns (como um usuário revogando a permissão do aplicativo ou removendo sua conta do Windows, por exemplo) e tratá-los normalmente.

Remover uma conta armazenada

Se você persistir em uma conta da Web, convém dar aos usuários a capacidade de desassociar a conta deles ao seu aplicativo. Dessa forma, eles podem efetivamente "sair" do aplicativo: as informações da conta não serão mais carregadas automaticamente após o lançamento. Para fazer isso, primeiro remova todas as informações salvas da conta e do provedor do armazenamento. Em seguida, chame SignOutAsync para limpar o cache e invalidar quaisquer tokens existentes que seu aplicativo possa ter.

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

Adicionar provedores que não dão suporte ao WebAccountManager

Se você quiser integrar a autenticação de um serviço ao seu aplicativo, mas esse serviço não for compatível com WebAccountManager (Google+ ou Twitter, por exemplo), você ainda poderá adicionar manualmente esse provedor ao AccountsSettingsPane. Para fazer isso, crie um novo objeto WebAccountProvider e forneça seu próprio nome e .png ícone e, em seguida, adicione-o à lista WebAccountProviderCommands. Aqui está um código de esboço:

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
}

Observação

Isso apenas adiciona um ícone ao AccountsSettingsPane e executa o método especificado quando o ícone é clicado (GetTwitterTokenAsync, nesse caso). Você deve fornecer o código que lida com a autenticação real. Para obter mais informações, consulte Agente de autenticação da Web, que fornece métodos auxiliares para autenticação usando serviços REST.

Adicionar um cabeçalho personalizado

Você pode personalizar o painel de configurações da conta usando a propriedade HeaderText, desta forma:

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

Captura de tela da janela Escolher uma conta sem contas listadas e uma mensagem que diz que o My Awesome App funciona melhor se você estiver conectado.

Não exagere no texto do cabeçalho; Mantenha-o curto e doce. Se o seu processo de login for complicado e você precisar exibir mais informações, vincule o usuário a uma página separada usando um link personalizado.

Você pode adicionar comandos personalizados ao AccountsSettingsPane, que aparecem como links abaixo de seus WebAccountProviders com suporte. Os comandos personalizados são ótimos para tarefas simples relacionadas a contas de usuário, como exibir uma política de privacidade ou iniciar uma página de suporte para usuários com problemas.

Veja um exemplo:

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
}

Captura de tela da janela Escolha uma conta sem contas listadas e um link para uma Política de privacidade.

Teoricamente, você pode usar comandos de configurações para qualquer coisa. No entanto, sugerimos limitar seu uso a cenários intuitivos relacionados à conta, como os descritos acima.

Confira também

Namespace Windows.Security.Authentication.Web.Core

Namespace Windows.Security.Credentials

Classe AccountsSettingsPane

Agente de autenticação da Web

Exemplo de gerenciamento de conta da Web

Aplicativo Lunch Scheduler