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.

Proposta de valor do WAM

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.

Limitações do WAM

  • 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.

Pacote de integração do WAM

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.

Padrão de chamadas do WAM

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://learn.microsoft.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.

URI de redirecionamento

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}

Persistência de cache de token

É 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.

Conta para Logon Silencioso

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.

Identificadores da janela pai

Você deve configurar o MSAL com a janela à qual a experiência interativa deve estar vinculada, usando as APIs WithParentActivityOrWindow.

Aplicativos de interface do usuário

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.

Aplicativos de console

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

Solução de problemas

Mensagem de erro "O seletor da conta WAM não retornou uma conta"

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:

  1. Na barra de tarefas, clique com o botão direito do mouse em Iniciar e selecione Windows PowerShell (Admin).

  2. Se for solicitado por uma caixa de diálogo de Controle de Conta de Usuário, selecione Sim para iniciar o PowerShell.

  3. 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.

Problemas de conexão

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.

Amostra

Você pode encontrar uma amostra do WPF que usa o WAM no GitHub.

Próximas etapas

Vá para o próximo artigo desse cenário, Chamar uma API Web a partir do aplicativo da área de trabalho.