Gerenciador de Contas da Web

Este artigo descreve como usar o AccountsSettingsPane para conectar seu aplicativo Plataforma Universal do Windows (UWP) a provedores de identidade externos, como a Microsoft ou o Facebook, usando as APIs do Gerenciador de Contas da Web do Windows 10 e Windows 11. Você aprenderá a solicitar a permissão de um usuário para usar a conta da Microsoft dele, obter um token de acesso e usá-lo para realizar operações básicas (como obter dados de perfil ou carregar arquivos na conta do OneDrive). As etapas são semelhantes para obter permissão do usuário e acesso 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 de WebAccountManagement no GitHub.

Prepare-se para começar

Primeiro, crie um aplicativo em branco no Visual Studio.

Segundo, para conectar a provedores de identidade, será necessário associar seu aplicativo à Loja. Para fazer isso, clique com o botão direito do mouse em seu projeto, escolha Loja/Publicar>Aplicativo associado com a loja e siga as instruções do assistente.

Terceiro, crie uma interface do usuário 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 conectado ao botão no code-behind:

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

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

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 conta

O sistema fornece uma interface do usuário interna para gerenciar provedores de identidade e contas da Web chamada de AccountSettingsPane. Você pode exibi-la da seguinte forma:

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

Se você executar o aplicativo e clicar no botão "Fazer logon", uma janela vazia deverá ser exibida.

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

O painel está vazio porque o sistema fornece somente um shell de interface do usuário - cabe ao desenvolvedor popular o painel de forma programática com os provedores de identidade.

Dica

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

Registro para AccountCommandsRequested

Para adicionar comandos ao painel, começamos o registro para o manipulador de eventos AccountCommandsRequested. Isso instrui o sistema a executar nossa lógica de build quando o usuário solicita para ver o painel (por exemplo, clica no botão XAML).

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

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 frequentemente; por isso, fazer o registro e o cancelamento de registro do manipulador de eventos dessa maneira ajuda a prevenir perda de memória. Dessa forma, o painel personalizado estará somente na memória quando houver uma grande possibilidade de que um usuário o solicitará (porque ele está em uma página de "configurações" ou "logon", por exemplo).

Criar o painel de configurações da conta

O método BuildPaneAsync é chamado sempre que o AccountSettingsPane é mostrado. Esse é o local onde colocaremos o código para personalizar os comandos exibidos no painel.

Comece obtendo um adiamento. Isso diz para o sistema adiar a exibição do AccountsSettingsPane até que sua criação seja concluída.

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 para o 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 "consumers" ao parâmetro opcional authority. Isso ocorre porque a Microsoft fornece dois tipos diferentes de autenticação - Contas da Microsoft (MSA) para "consumers", e Azure Active Directory (AAD) para "organizations". A autoridade "consumers" indica que queremos a opção MSA. Se você estiver desenvolvendo um aplicativo empresarial, use a string "organizations".

Por fim, adicione o provedor ao AccountsSettingsPane criando um novo WebAccountProviderCommand da seguinte forma:

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 o novo WebAccountProviderCommand ainda não existe (ele será criado na próxima etapa), por isso sinta-se à vontade para adicioná-lo como um método vazio por enquanto.

Execute o código acima, e o painel deve ter a seguinte aparência:

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

Solicitar um token

Assim que a opção da Conta da Microsoft for exibida no AccountsSettingsPane, será necessário manipular o que acontecerá quando o usuário a selecionar. Registramos nosso método GetMsaToken para ser acionado quando o usuário optar por fazer logon com a Conta da Microsoft, por isso obteremos o token ali.

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 cadeia de caracteres ""wl.basic" para o parâmetro de escopo. Escopo representa o tipo de informação que você está solicitando do serviço em um usuário específico. Determinados escopos fornecem acesso somente a informações básicas do usuário, como nome e email, enquanto outros escopos podem conceder acesso a informações confidenciais, como as fotos do usuário ou a caixa de entrada de email. Em geral, seu app deve usar o escopo menos permissivo necessário para obter sua função. Os provedores de serviço fornecerão documentação sobre quais escopos são necessários para obter tokens para uso com os 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 Web, o que impede incompatibilidades de conta no cache.

Se estiver desenvolvendo um aplicativo empresarial, você 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 normais. Nesse cenário, use o código a seguir:

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 MSA, mas o código para AAD é muito semelhante. Para saber mais sobre 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 de sua solicitação. Se a solicitação foi bem-sucedida, 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 app à Store, conforme descrito na etapa um. Seu aplicativo não conseguirá obter um token se você ignorou essa etapa.

Quando você tiver um token, poderá usá-lo para chamar a API do provedor. No código abaixo, chamaremos a API do Microsoft Live de informações do usuário para obter informações básicas sobre o usuário e exibi-las em nossa interface do usuário. Observe, porém, que na maioria dos casos é recomendável que você armazene o token obtido uma vez e depois o utilize 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;
		}
	}
}

O modo como você chama diversas APIs REST varia de acordo com o provedor; consulte a documentação de API do provedor para obter informações sobre como usar seu token.

Armazenar a conta para uso futuro

Tokens são úteis para obter imediatamente informações sobre um usuário, mas eles geralmente têm tempo de vida variável - os tokens MSA, por exemplo, são válidos por algumas horas apenas. Felizmente, não é necessário mostrar novamente o AccountsSettingsPane sempre que um token expirar. Quando um usuário autoriza seu aplicativo uma vez, você pode armazenar as informações da conta do usuário para uso futuro.

Para fazer isso, use a classe WebAccount. A 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; 
	}
}

Quando você tiver um WebAccount, poderá armazená-la com facilidade. 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 app.

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 semelhante ao 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 pouco antes do código que cria o AccountsSettingsPane. Se o token for obtido em segundo plano, não será necessário 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();
	}
}

Obter um token silenciosamente é bastante simples, por isso você deve usar esse processo para atualizar o token entre sessões em vez de armazenar em cache um token existente (pois esse token pode expirar a qualquer momento).

Observação

O exemplo acima aborda somente os casos básicos de êxito e falha. Seu aplicativo também deve considerar cenários incomuns (como um usuário que revoga a permissão do aplicativo ou remove sua conta do Windows, por exemplo) e manipulá-los corretamente.

Remover uma conta armazenada

Se você persistir uma conta da Web, talvez queira oferecer aos usuários a capacidade de desassociar a conta ao app. Dessa forma, eles podem efetivamente "fazer logoff" do aplicativo: suas informações de conta não serão mais carregadas automaticamente após a inicialização. Para fazer isso, primeiro remova qualquer conta salva e as informações do armazenamento. Em seguida, chame SignOutAsync para limpar o cache e invalide qualquer token existente que seu app 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 em seu aplicativo, mas esse serviço não der suporte a WebAccountManager - Google+ ou Twitter, por exemplo - você ainda poderá adicionar manualmente esse provedor ao AccountsSettingsPane. Para isso, crie um novo objeto WebAccountProvider e forneça um nome e ícone .png, depois adicione-o à lista WebAccountProviderCommands. Veja um código 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
}

Observação

Isso apenas adiciona um ícone ao AccountsSettingsPane e executa o método especificado quando o ícone for clicado (GetTwitterTokenAsync, neste caso). Você deve fornecer o código que manipula 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, da seguinte 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 informando que Meu Aplicativo Incrível funciona melhor se você estiver conectado.

Não exagere com texto de cabeçalho; seja conciso e direto. Se o processo de logon 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 seu WebAccountProviders com suporte. 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 os usuários que estão 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 Escolher uma conta sem contas listadas e um link para uma política de Privacidade.

Teoricamente, você pode usar comandos de configurações para tudo. 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 contas da Web

App Lunch Scheduler