Aplicación de escritorio que llama a las API web: adquisición de un token mediante WAM

La Biblioteca de autenticación de Microsoft (MSAL) llama al Administrador de cuentas web (WAM), un componente de Windows 10+ que actúa como agente de autenticación. El agente permite a los usuarios de la aplicación beneficiarse de la integración con cuentas conocidas para Windows, como la cuenta que inició sesión en la sesión de Windows.

Propuesta de valor de WAM

El uso de un agente de autenticación como WAM tiene varias ventajas:

  • Seguridad mejorada. Consulte Protección de tókenes.
  • Compatibilidad con Windows Hello, acceso condicional y claves FIDO.
  • Integración con la vista de cuentas y correo electrónico de Windows.
  • Inicio de sesión único rápido.
  • Capacidad de iniciar sesión automáticamente con la cuenta de Windows actual.
  • Correcciones de errores y mejoras enviadas con Windows.

Limitaciones de WAM

  • WAM está disponible en Windows 10 y versiones posteriores y en Windows Server 2019 y versiones posteriores. En Mac, Linux y en versiones anteriores de Windows, MSAL recurre automáticamente a un explorador.
  • No se admiten las autoridades de Azure Active Directory B2C (Azure AD B2C) y Servicios de federación de Active Directory (AD FS). MSAL recurre a un explorador.

Paquete de integración de WAM

La mayoría de aplicaciones deben hacer referencia al paquete Microsoft.Identity.Client.Broker para usar esta integración. Las aplicaciones .NET MAUI no tienen que hacerlo, ya que la funcionalidad está dentro de MSAL cuando el destino es net6-windows y versiones posteriores.

Patrón de llamada de WAM

Puede usar el siguiente patrón para 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                                  
    }

Si no hay ningún agente presente (por ejemplo, Windows 8.8.1, Mac o Linux), MSAL recurre a un explorador, donde se aplican las reglas del identificador URI de redireccionamiento.

URI de redireccionamiento

No es necesario configurar los identificadores URI de redireccionamiento de WAM en MSAL, pero debe configurarlos en el registro de la aplicación:

ms-appx-web://microsoft.aad.brokerplugin/{client_id}

Persistencia de la memoria caché de tokens

Es importante conservar la caché de tókenes de MSAL porque MSAL sigue almacenando los tókenes de id. y los metadatos de la cuenta allí. Para más información, consulte Serialización de la caché de tokens en MSAL.NET.

Cuenta para el inicio de sesión automático

Para buscar una cuenta para el inicio de sesión automático, se recomienda este patrón:

  • Si el usuario inició sesión anteriormente, use esa cuenta. Si no es así, use PublicClientApplication.OperatingSystemAccount para la cuenta de Windows actual.
  • Permita que el usuario cambie a otra cuenta al iniciar sesión de manera interactiva.

Identificadores de ventana primaria

Debe configurar MSAL con la ventana a la que se debe asociar la experiencia interactiva primaria mediante las API de WithParentActivityOrWindow.

Aplicaciones de interfaz de usuario

Para aplicaciones de interfaz de usuario como Windows Forms (WinForms), Windows Presentation Foundation (WPF) o biblioteca de interfaz de usuario de Windows versión 3 (WinUI3), consulte Recuperar un identificador de ventana.

Aplicaciones de consola

Para aplicaciones de consola, la configuración es más compleja debido a la ventana del terminal y sus pestañas. Use el código siguiente:

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

Solución de problemas

Mensaje de error "El selector de cuentas de WAM no ha devuelto una cuenta"

El mensaje "El selector de cuentas de WAM no ha devuelto una cuenta" indica que el usuario de la aplicación ha cerrado el cuadro de diálogo que muestra las cuentas o que el propio cuadro diálogo se ha bloqueado. Puede producirse un bloqueo si AccountsControl, un control de Windows, se registra incorrectamente en Windows. Para resolver este problema:

  1. En la barra de tareas, haga clic con el botón derecho en Inicio y, luego, seleccione Windows PowerShell (Administrador).

  2. Si se le muestra un cuadro de diálogo Control de cuentas de usuario, seleccione para iniciar PowerShell.

  3. Copie y ejecute el siguiente script:

    if (-not (Get-AppxPackage Microsoft.AccountsControl)) { Add-AppxPackage -Register "$env:windir\SystemApps\Microsoft.AccountsControl_cw5n1h2txyewy\AppxManifest.xml" -DisableDevelopmentMode -ForceApplicationShutdown } Get-AppxPackage Microsoft.AccountsControl
    

Mensaje de error "MsalClientException: ErrorCode: wam_runtime_init_failed" durante la implementación de un solo archivo

Es posible que vea el siguiente error al empaquetar la aplicación en un conjunto de archivos ú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

Este error indica que los archivos binarios nativos de Microsoft.Identity.Client.NativeInterop no se empaquetaron en el conjunto de archivos único. A fin de insertar esos archivos para la extracción y obtener un archivo de salida, establezca la propiedad IncludeNativeLibrariesForSelfExtract en true. Obtenga más información sobre cómo empaquetar archivos binarios nativos en un único archivo.

Problemas de conexión

Si el usuario de la aplicación ve regularmente un mensaje de error similar a "Compruebe la conexión e inténtelo de nuevo", consulte la guía de solución de problemas de Office. Esa guía de solución de problemas también usa el agente.

Muestra

Puede encontrar un ejemplo de WPF que use WAM en GitHub.

Pasos siguientes

Avance al siguiente artículo de este escenario, Llamada a una API web desde la aplicación de escritorio.