Aplicación de escritorio que llama a las API web: adquisición de un token de forma interactiva

El ejemplo siguiente muestra un código mínimo para obtener un token de forma interactiva para leer el perfil del usuario con Microsoft Graph.

Código en MSAL.NET

string[] scopes = new string[] { "user.read" };

var app = PublicClientApplicationBuilder.Create("YOUR_CLIENT_ID")
    .WithDefaultRedirectUri()
    .Build();

var accounts = await app.GetAccountsAsync();

AuthenticationResult result;
try
{
    result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
      .ExecuteAsync();
}
catch (MsalUiRequiredException)
{
    result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
}

Parámetros obligatorios

AcquireTokenInteractive solo tiene un parámetro obligatorio: scopes. Contiene una enumeración de cadenas que definen los ámbitos para los que se requiere un token. Si el token es para Microsoft Graph, puedes encontrar los ámbitos requeridos en la referencia de API de cada API de Microsoft Graph en la sección denominada "Permisos". Por ejemplo, para enumerar los contactos del usuario, debes usar tanto User.Read como Contacts.Read y como el ámbito. Para más información, consulte Referencia de permisos de Microsoft Graph.

Tanto en las aplicaciones de escritorio como en las móviles, es importante especificar el elemento primario mediante .WithParentActivityOrWindow. En muchos casos, es un requisito y MSAL producirá excepciones.

Para las aplicaciones de escritorio, consulta los Identificadores de ventana primarios.

En el caso de las aplicaciones móviles, proporciona Activity (Android) o UIViewController (iOS).

Parámetros opcionales en MSAL.NET

WithParentActivityOrWindow

La interfaz de usuario es importante porque es interactiva. AcquireTokenInteractive tiene un parámetro opcional específico que puede especificar (para las plataformas que lo admiten) la interfaz de usuario principal. Cuando se usa .WithParentActivityOrWindow en una aplicación de escritorio, tiene un tipo diferente que depende de la plataforma.

Como alternativa, puede omitir el parámetro de ventana principal opcional para crear una ventana, si no deseas controlar dónde aparece el cuadro de diálogo de inicio de sesión en la pantalla. Esta opción se aplica a las aplicaciones que se basan en una línea de comandos, se utilizan para pasar llamadas a cualquier otro servicio de back-end y no necesitan ninguna ventana para la interacción del usuario.

// net45
WithParentActivityOrWindow(IntPtr windowPtr)
WithParentActivityOrWindow(IWin32Window window)

// Mac
WithParentActivityOrWindow(NSWindow window)

// .NET Standard (this will be on all platforms at runtime, but only on .NET Standard platforms at build time)
WithParentActivityOrWindow(object parent).

Comentarios:

  • En .NET Standard, el valor object esperado es Activity en Android, UIViewController en iOS, NSWindow en Mac y IWin32Window o IntPr en Windows.

  • En Windows, debe llamar a AcquireTokenInteractive desde el subproceso de interfaz de usuario para que el explorador integrado obtenga el contexto de sincronización de la interfaz de usuario adecuado. No llamar desde el subproceso de la interfaz de usuario puede provocar que los mensajes no se bombeen correctamente y provocar escenarios de interbloqueo con la interfaz de usuario. Una forma de llamar a la Biblioteca de autenticación de Microsoft (MSAL) desde el subproceso de la interfaz de usuario si aún no estás en el subproceso de la interfaz de usuario es usar Dispatcher en Windows Presentation Foundation (WPF).

  • Si usa WPF, para obtener una ventana de un control WPF puede usar la clase WindowInteropHelper.Handle. Así, la llamada procede de un control WPF (this):

    result = await app.AcquireTokenInteractive(scopes)
                      .WithParentActivityOrWindow(new WindowInteropHelper(this).Handle)
                      .ExecuteAsync();
    

WithPrompt

Se utiliza WithPrompt() para controlar la interactividad con el usuario especificando un aviso. Puedes controlar el comportamiento exacto mediante la estructura Microsoft.Identity.Client.Prompt.

La estructura define las constantes siguientes:

  • SelectAccount obliga al servicio de token de seguridad (STS) a presentar el cuadro de diálogo de selección de cuenta que contiene cuentas para las que el usuario tiene una sesión. Es la opción predeterminada. Es útil cuando desea permitir que los usuarios elijan entre diferentes identidades.

    Esta opción dirige a MSAL para que envíe prompt=select_account al proveedor de identidades. Proporciona la mejor experiencia posible en función de la información disponible, como la cuenta y la presencia de una sesión para el usuario. No lo cambies a menos que tengas una buena razón.

  • Consent permite obligar al usuario a solicitar el consentimiento, incluso si la aplicación lo concedió antes. En este caso, MSAL envía prompt=consent al proveedor de identidades. Puedes usar esta opción en algunas aplicaciones centradas en la seguridad donde el gobierno de la organización exige que aparezca el cuadro de diálogo de consentimiento cada vez que el usuario abre la aplicación.

  • ForceLogin permite hacer que la aplicación solicite al usuario las credenciales, incluso si esta solicitud de usuario puede no ser necesaria. Esta opción puede ser útil para permitir que el usuario vuelva a iniciar sesión si falla la adquisición del token. En este caso, MSAL envía prompt=login al proveedor de identidades. Las organizaciones a veces usan esta opción en aplicaciones centradas en la seguridad donde la gobernanza exige que los usuarios inicien sesión cada vez que acceden a partes específicas de una aplicación.

  • Create desencadena una experiencia de registro para identidades externas mediante el envío de prompt=create al proveedor de identidad. Las aplicaciones de Azure Active Directory B2C (Azure AD B2C) no deben enviar este mensaje. Para más información, consulte Incorporación de un flujo de usuario de registro de autoservicio a una aplicación.

  • Never (solo para .NET 4.5 y Windows Runtime) no pregunta al usuario. En su lugar, intenta utilizar la cookie almacenada en la vista web incrustada oculta.

    Es posible que se produzca un error en el uso de esta opción. En ese caso, AcquireTokenInteractive genera una excepción para notificarte que necesitas una interacción con la interfaz de usuario. Luego, usa otro parámetro Prompt.

  • NoPrompt no envía ningún símbolo del sistema al proveedor de identidades. El proveedor de identidades decide qué experiencia de inicio de sesión es la mejor para el usuario (inicio de sesión único o seleccionar cuenta).

    Esta opción es obligatoria para editar directivas de perfil en Azure AD B2C. Para más información, consulte Información específica sobre Azure AD B2C.

WithUseEmbeddedWebView

Este método le permite especificar si quiere forzar el uso de una vista web insertada o una vista web del sistema (si está disponible). Para más información, consulte Uso de exploradores web.

var result = await app.AcquireTokenInteractive(scopes)
                    .WithUseEmbeddedWebView(true)
                    .ExecuteAsync();

WithExtraScopeToConsent

Este modificador es para escenarios avanzados en los que desea que el usuario dé su consentimiento por adelantado a varios recursos y no quiere usar el consentimiento incremental. Normalmente, los desarrolladores usan el consentimiento incremental con MSAL.NET y el Plataforma de identidad de Microsoft. Para más información, consulta Cómo tener el consentimiento del usuario por adelantado para varios recursos.

var result = await app.AcquireTokenInteractive(scopesForCustomerApi)
                     .WithExtraScopeToConsent(scopesForVendorApi)
                     .ExecuteAsync();

WithCustomWebUi

Una interfaz de usuario web es un mecanismo para invocar un explorador. Este mecanismo puede ser un control WebBrowser de interfaz de usuario dedicado o una forma de delegar la apertura del explorador. MSAL proporciona implementaciones de interfaz de usuario web para la mayoría de las plataformas, pero es posible que desee alojar el navegador usted mismo en estos casos:

  • Tienes plataformas que MSAL no cubre explícitamente, como Blazor, Unity y Mono en equipos de escritorio.
  • Quiere probar la aplicación en la interfaz de usuario y usar un explorador automatizado que se pueda emplear con Selenium.
  • El explorador y la aplicación que ejecutan MSAL están en procesos independientes.

Para lograr esto, le das a MSAL start Url, que debe mostrarse en un navegador para que los usuarios puedan ingresar elementos como su nombre de usuario. Una vez que finaliza la autenticación, la aplicación debe volver a pasar a MSAL end Url, que contiene un código que proporciona Microsoft Entra ID. El host de end Url siempre es redirectUri. Para interceptar end Url, realice una de las siguientes acciones:

  • Supervise los redireccionamientos del explorador hasta que se alcance redirect Url.
  • Haz que el navegador redirija a una URL que supervises.

WithCustomWebUi es un punto de extensibilidad que se puede usar para proporcionar una interfaz de usuario propia en aplicaciones cliente públicas. También puedes permitir que los usuarios pasen por el punto de conexión /Authorize del proveedor de identidad y que inicien sesión y den su consentimiento. Después, MSAL.NET puede canjear el código de autenticación y obtener un token.

Por ejemplo, se puede usar WithCustomWebUi en Visual Studio para que las aplicaciones de Electron (por ejemplo, Visual Studio Feedback) proporcionen la interacción web, pero deja que MSAL.NET haga la mayor parte del trabajo. También puedes usar WithCustomWebUi si quieres proporcionar automatización de la interfaz de usuario.

En las aplicaciones cliente públicas, MSAL.NET usa la norma Proof Key for Code Exchange (PKCE) para garantizar que se respeta la seguridad. Solo MSAL.NET puede canjear el código. Para más información, consulte RFC 7636 - Proof Key for Code Exchange por parte de clientes públicos de OAuth.

using Microsoft.Identity.Client.Extensions;
Usar WithCustomWebUi

Para usar WithCustomWebUI, sigue estos pasos:

  1. Implemente la interfaz ICustomWebUi. Para obtener más información, consulta esta página de GitHub.

  2. Implementa un AcquireAuthorizationCodeAsyncmétodo y acepta la URL del código de autorización que calcula MSAL.NET.

  3. Deja que el usuario pase por la interacción con el proveedor de identidad y devuelve la URL que el proveedor de identidad usó para devolver la llamada a la implementación, junto con el código de autorización. Si tienes problemas, tu implementación debe generar una excepción MsalExtensionException para cooperar con MSAL.

  4. En la llamada a AcquireTokenInteractive, usa el modificador .WithCustomUI() pasando la instancia de la interfaz de usuario web personalizada:

    result = await app.AcquireTokenInteractive(scopes)
                      .WithCustomWebUi(yourCustomWebUI)
                      .ExecuteAsync();
    

El equipo de MSAL.NET ha vuelto a escribir las pruebas de interfaz de usuario para usar este mecanismo de extensibilidad. Si te interesa, vea la clase SeleniumWebUI en el código fuente de MSAL.NET.

Una gran experiencia con SystemWebViewOptions

En SystemWebViewOptions de MSAL.NET 4.1, puede especificar:

  • El URI para ir a (BrowserRedirectError) o el fragmento de HTML para mostrar (HtmlMessageError) si aparecen errores de inicio de sesión o consentimiento en el explorador web del sistema.
  • El URI para ir a (BrowserRedirectSuccess) o el fragmento de HTML para mostrar (HtmlMessageSuccess) si el inicio de sesión o el consentimiento son correctos.
  • La acción que se va a ejecutar para iniciar el explorador del sistema. Puede proporcionar una implementación propia si establece el delegado OpenBrowserAsync. La clase también proporciona una implementación predeterminada para dos exploradores: OpenWithEdgeBrowserAsync para Microsoft Edge y OpenWithChromeEdgeBrowserAsync para Microsoft Edge en Chromium.

Para usar esta estructura, escriba algo como esto:

IPublicClientApplication app;
...

options = new SystemWebViewOptions
{
 HtmlMessageError = "<b>Sign-in failed. You can close this tab ...</b>",
 BrowserRedirectSuccess = "https://contoso.com/help-for-my-awesome-commandline-tool.html"
};

var result = app.AcquireTokenInteractive(scopes)
                .WithEmbeddedWebView(false)       // The default in .NET
                .WithSystemWebViewOptions(options)
                .Build();

Otros parámetros opcionales

Para más información sobre los demás parámetros opcionales de AcquireTokenInteractive, consulta AcquireTokenInteractiveParameterBuilder.

Pasos siguientes

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