Aplicativo desktop que chama APIs Web: adquira um token usando o WAM
A Biblioteca de Autenticação da Microsoft (MSAL) chama o WAM (Web Account Manager), um componente do Windows 10+ que atua como um corretor de autenticação. O agente permite que os usuários do seu aplicativo se beneficiem da integração com contas conhecidas do Windows, como a conta com a qual você entrou em sua sessão do Windows.
Usar um agente de autenticação como o WAM tem vários benefícios:
- Segurança aprimorada. Consulte Proteção de token.
- Suporte para Windows Hello, acesso condicional e chaves FIDO.
- Integração com o modo de exibição Email e contas do Windows.
- Logon único rápido.
- Capacidade de entrar silenciosamente com a conta atual do Windows.
- Correções de bugs e aprimoramentos fornecidos com o Windows.
- O WAM está disponível no Windows 10 e posterior e no Windows Server 2019 e posterior. No Mac, Linux e versões anteriores do Windows, o MSAL recai automaticamente em um navegador.
- As autoridades do Azure Active Directory B2C (Azure AD B2C) e dos Serviços de Federação do Active Directory (AD FS) não têm suporte. A MSAL volta para um navegador.
A maioria dos aplicativos precisa fazer referência ao pacote Microsoft.Identity.Client.Broker
para usar essa integração. Os aplicativos .NET MAUI não precisam fazer isso, porque a funcionalidade está dentro do MSAL quando o destino é net6-windows
e posterior.
Você pode usar o seguinte padrão para o WAM:
// 1. Configuration - read below about redirect URI
var pca = PublicClientApplicationBuilder.Create("client_id")
.WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows))
.Build();
// Add a token cache; see https://video2.skills-academy.com/azure/active-directory/develop/msal-net-token-cache-serialization?tabs=desktop
// 2. Find an account for silent login
// Is there an account in the cache?
IAccount accountToLogin = (await pca.GetAccountsAsync()).FirstOrDefault();
if (accountToLogin == null)
{
// 3. No account in the cache; try to log in with the OS account
accountToLogin = PublicClientApplication.OperatingSystemAccount;
}
try
{
// 4. Silent authentication
var authResult = await pca.AcquireTokenSilent(new[] { "User.Read" }, accountToLogin)
.ExecuteAsync();
}
// Cannot log in silently - most likely Azure AD would show a consent dialog or the user needs to re-enter credentials
catch (MsalUiRequiredException)
{
// 5. Interactive authentication
var authResult = await pca.AcquireTokenInteractive(new[] { "User.Read" })
.WithAccount(accountToLogin)
// This is mandatory so that WAM is correctly parented to your app; read on for more guidance
.WithParentActivityOrWindow(myWindowHandle)
.ExecuteAsync();
// Consider allowing the user to re-authenticate with a different account, by calling AcquireTokenInteractive again
}
Se um corretor não estiver presente (por exemplo, Windows 8.1, Mac ou Linux), o MSAL retornará para um navegador, onde as regras de redirecionamento de URI se aplicam.
Você não precisa configurar URIs de redirecionamento do WAM no MSAL, mas precisa configurá-los no registro do aplicativo:
ms-appx-web://microsoft.aad.brokerplugin/{client_id}
É importante manter o cache de tokens MSAL porque o MSAL continua armazenando os tokens de ID e metadados da conta lá. Para obter mais informações, confira Serialização do cache de token no MSAL.NET.
Para encontrar uma conta para logon silencioso, recomendamos esse padrão:
- Se o usuário tiver feito logon anteriormente, utilize essa conta. Caso contrário, use
PublicClientApplication.OperatingSystemAccount
para a conta atual do Windows. - Permitir que o usuário altere para uma conta diferente fazendo logon interativamente.
Você deve configurar o MSAL com a janela à qual a experiência interativa deve estar vinculada, usando as APIs WithParentActivityOrWindow
.
Para aplicativos de interface do usuário como Windows Forms (WinForms), Windows Presentation Foundation (WPF) ou Windows UI Library versão 3 (WinUI3), consulte Recuperar um identificador de janela.
Para aplicativos de console, a configuração é mais envolvida por causa da janela do terminal e suas guias. Use o seguinte código:
enum GetAncestorFlags
{
GetParent = 1,
GetRoot = 2,
/// <summary>
/// Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.
/// </summary>
GetRootOwner = 3
}
/// <summary>
/// Retrieves the handle to the ancestor of the specified window.
/// </summary>
/// <param name="hwnd">A handle to the window whose ancestor will be retrieved.
/// If this parameter is the desktop window, the function returns NULL. </param>
/// <param name="flags">The ancestor to be retrieved.</param>
/// <returns>The return value is the handle to the ancestor window.</returns>
[DllImport("user32.dll", ExactSpelling = true)]
static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
// This is your window handle!
public IntPtr GetConsoleOrTerminalWindow()
{
IntPtr consoleHandle = GetConsoleWindow();
IntPtr handle = GetAncestor(consoleHandle, GetAncestorFlags.GetRootOwner );
return handle;
}
A mensagem "O Seletor de Conta do WAM não retornou uma conta" indica que o usuário do aplicativo fechou a caixa de diálogo que exibe as contas ou a caixa de diálogo em si travou. Uma falha pode ocorrer se AccountsControl
, um controle do Windows, estiver registrado incorretamente no Windows. Para resolver esse problema:
Na barra de tarefas, clique com o botão direito do mouse em Iniciar e selecione Windows PowerShell (Admin).
Se for solicitado por uma caixa de diálogo de Controle de Conta de Usuário, selecione Sim para iniciar o PowerShell.
Copie e execute o seguinte script:
if (-not (Get-AppxPackage Microsoft.AccountsControl)) { Add-AppxPackage -Register "$env:windir\SystemApps\Microsoft.AccountsControl_cw5n1h2txyewy\AppxManifest.xml" -DisableDevelopmentMode -ForceApplicationShutdown } Get-AppxPackage Microsoft.AccountsControl
"MsalClientException: ErrorCode: wam_runtime_init_failed" mensagem de erro durante uma implantação de arquivo único
Você pode ver o seguinte erro ao empacotar seu aplicativo em um pacote de arquivo único:
MsalClientException: wam_runtime_init_failed: The type initializer for 'Microsoft.Identity.Client.NativeInterop.API' threw an exception. See https://aka.ms/msal-net-wam#troubleshooting
Esse erro indica que os binários nativos do Microsoft.Identity.Client.NativeInterop não foram empacotados no pacote de arquivo único. Para inserir esses arquivos para extração e obter um arquivo de saída, defina a propriedade IncludeNativeLibrariesForSelfExtract
como true
. Leia mais sobre como empacotar binários nativos em um único arquivo.
Se o usuário do aplicativo vir regularmente uma mensagem de erro semelhante a "Verifique sua conexão e tente novamente", consulte o guia de solução de problemas do Office. Esse guia de solução de problemas também utiliza o corretor.
Você pode encontrar uma amostra do WPF que usa o WAM no GitHub.
Vá para o próximo artigo desse cenário, Chamar uma API Web a partir do aplicativo da área de trabalho.