Tutorial: Inicio de sesión de los usuarios en la aplicación de shell de .NET MAUI mediante un inquilino externo
Este tutorial es la parte final de una serie que muestra cómo crear una aplicación shell de .NET Multi-platform App UI (.NET MAUI) y prepararla para la autenticación mediante el Centro de administración de Microsoft Entra. En la parte 2 de esta serie agregó un asistente de cliente personalizado de la Biblioteca de autenticación de Microsoft (MSAL) para inicializar el SDK de MSAL, instalar las bibliotecas necesarias e incluir un recurso de imagen. En este paso final se muestra cómo agregar código de inicio de sesión y cierre de sesión en .NET MAUI y ejecutar la aplicación de shell en la plataforma Android.
En este tutorial, hará lo siguiente:
- Agregar inicio y cierre de sesión.
- Modificar el shell de la aplicación.
- Agregar código específico de plataforma.
- Agregar la configuración de la aplicación.
- Ejecute y pruebe la aplicación de shell MAUI de .NET.
Requisitos previos
Adición de inicio y cierre de sesión
La interfaz de usuario (UI) de una aplicación .NET MAUI se construye de objetos que se asignan a los controles nativos de cada plataforma de destino. Los grupos de controles principales que se usan para crear la interfaz de usuario de una aplicación .NET MAUI son páginas, diseños y vistas.
Agregar página de vista principal
En los próximos pasos organizaremos nuestro código para que main view
esté definido.
Elimine MainPage.xaml y MainPage.xaml.cs del proyecto, ya no son necesarios. En el panel Explorador de soluciones, busque la entrada de MainPage.xaml, haga clic con el botón derecho en ella y seleccione Eliminar.
Haga clic con el botón derecho en el proyecto SignInMaui y seleccione Agregar>Nueva carpeta. Asigne a la carpeta el nombre Vistas.
Haga clic con el botón derecho en Vistas .
Seleccione Agregar>Nuevo elemento....
Seleccione .NET MAUI en la lista de plantillas.
Seleccione la plantilla ContentPage (XAML) de .NET MAUI. Asigne al archivo el nombre MainView.xaml.
Seleccione Agregar.
El archivo MainView.xaml se abrirá en una nueva pestaña de documento, mostrando todo el marcado XAML que representa la interfaz de usuario de la página. Reemplace el marcado XAML por el siguiente marcado:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SignInMaui.Views.MainView" Title="Microsoft Entra External ID" > <Shell.BackButtonBehavior> <BackButtonBehavior IsVisible="False" IsEnabled="False" /> </Shell.BackButtonBehavior> <ScrollView> <VerticalStackLayout Spacing="25" Padding="30,0" VerticalOptions="Center"> <Image Source="external_id.png" SemanticProperties.Description="External ID" HeightRequest="200" HorizontalOptions="Center" /> <Label Text="CIAM" SemanticProperties.HeadingLevel="Level1" FontSize="26" HorizontalOptions="Center" /> <Label Text="MAUI sample" SemanticProperties.HeadingLevel="Level1" FontSize="26" HorizontalOptions="Center" /> <Button x:Name="SignInButton" Text="Sign In" SemanticProperties.Hint="Sign In" Clicked="OnSignInClicked" HorizontalOptions="Center" IsEnabled="False"/> </VerticalStackLayout> </ScrollView> </ContentPage>
Guarde el archivo.
Vamos a desglosar las partes clave de los controles XAML colocados en la página:
<ContentPage>
es el objeto raíz de la clase MainView.<VerticalStackLayout>
es el objeto secundario de ContentPage. Este control de diseño organiza sus elementos secundarios verticalmente, uno después del otro.<Image>
muestra una imagen, en este caso usa el azureactive_directory.png_ que descargó anteriormente.<Label>
controla la visualización del texto.<Button>
el usuario puede presionarlo, lo que genera el eventoClicked
. Puede ejecutar código en respuesta al eventoClicked
.Clicked="OnSignInClicked"
el eventoClicked
del botón se asigna al controlador de eventosOnSignInClicked
, que se definirá en el archivo de código subyacente. La creará en el paso siguiente.
Controlar el evento OnSignInClicked
El siguiente paso consiste en agregar el código para el evento del botón Clicked
.
En el panel Explorador de soluciones de Visual Studio, expanda el archivo MainView.xaml para mostrar su archivo de código subyacente mainView.xaml.cs. Abra MainView.xaml.cs y reemplace el contenido del archivo por el siguiente código:
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using SignInMaui.MSALClient; using Microsoft.Identity.Client; namespace SignInMaui.Views { public partial class MainView : ContentPage { public MainView() { InitializeComponent(); IAccount cachedUserAccount = PublicClientSingleton.Instance.MSALClientHelper.FetchSignedInUserFromCache().Result; _ = Dispatcher.DispatchAsync(async () => { if (cachedUserAccount == null) { SignInButton.IsEnabled = true; } else { await Shell.Current.GoToAsync("claimsview"); } }); } private async void OnSignInClicked(object sender, EventArgs e) { await PublicClientSingleton.Instance.AcquireTokenSilentAsync(); await Shell.Current.GoToAsync("claimsview"); } protected override bool OnBackButtonPressed() { return true; } } }
La clase
MainView
es una página de contenido responsable de mostrar la vista principal de la aplicación. En el constructor, recupera la cuenta de usuario en caché utilizando elMSALClientHelper
de la instanciaPublicClientSingleton
y habilita el botón de inicio de sesión, si no se encuentra ninguna cuenta de usuario en caché.Cuando se hace clic en el botón de inicio de sesión, llama al método
AcquireTokenSilentAsync
para adquirir un token de forma silenciosa y navega a la páginaclaimsview
mediante el métodoShell.Current.GoToAsync
. Además, el métodoOnBackButtonPressed
se invalida para devolver true, lo que indica que el botón atrás está deshabilitado para esta vista.
Agregar página de vista de reclamaciones
Los siguientes pasos organizarán el código para que la página ClaimsView
quede definida. La página mostrará las notificaciones del usuario que se encuentran en el token de Id.
En el panel Explorador de soluciones de Visual Studio, haga clic con el botón derecho en Vistas.
Seleccione Agregar>Nuevo elemento....
Seleccione .NET MAUI en la lista de plantillas.
Seleccione la plantilla ContentPage (XAML) de .NET MAUI. Asigne al archivo el nombre ClaimsView.xaml.
Seleccione Agregar.
El archivo ClaimsView.xaml se abrirá en una nueva pestaña de documento, mostrando todo el marcado XAML que representa la interfaz de usuario de la página. Reemplace el marcado XAML por el siguiente marcado:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SignInMaui.Views.ClaimsView" Title="ID Token View"> <Shell.BackButtonBehavior> <BackButtonBehavior IsVisible="False" IsEnabled="False" /> </Shell.BackButtonBehavior> <VerticalStackLayout> <Label Text="CIAM" FontSize="26" HorizontalOptions="Center" /> <Label Text="MAUI sample" FontSize="26" Padding="0,0,0,20" HorizontalOptions="Center" /> <Label Padding="0,20,0,0" VerticalOptions="Center" HorizontalOptions="Center" FontSize="18" Text="Claims found in ID token" /> <ListView ItemsSource="{Binding IdTokenClaims}" x:Name="Claims"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Grid Padding="0, 0, 0, 0"> <Label Grid.Column="1" Text="{Binding}" HorizontalOptions="Center" /> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button x:Name="SignOutButton" Text="Sign Out" HorizontalOptions="Center" Clicked="SignOutButton_Clicked" /> </VerticalStackLayout> </ContentPage>
Este código de marcado XAML representa el diseño de la interfaz de usuario de una vista de notificación en una aplicación .NET MAUI. Comienza definiendo
ContentPage
con un título y deshabilitando el comportamiento del botón atrás.Dentro de
VerticalStackLayout
, hay varios elementosLabel
que muestran texto estático, seguido de unListView
denominadoClaims
que enlaza a una colección denominadaIdTokenClaims
para mostrar las notificaciones encontradas en el token de Id. Cada notificación se representa dentro de unViewCell
mediante unDataTemplate
elemento y se muestra como un centradoLabel
dentro de una cuadrícula.Por último, hay un botón centrado
Sign Out
en la parte inferior del diseño, que desencadena el controlador de eventosSignOutButton_Clicked
cuando se hace clic en él.
Control de los datos de ClaimsView
El siguiente paso es agregar el código para controlar los datos ClaimsView
.
En el panel Explorador de soluciones de Visual Studio, expanda el archivo ClaimsView.xaml para mostrar su archivo de código subyacente ClaimsView.xaml.cs. Abra ClaimsView.xaml.cs y reemplace el contenido del archivo por el siguiente código:
using SignInMaui.MSALClient; using Microsoft.Identity.Client; namespace SignInMaui.Views; public partial class ClaimsView : ContentPage { public IEnumerable<string> IdTokenClaims { get; set; } = new string[] {"No claims found in ID token"}; public ClaimsView() { BindingContext = this; InitializeComponent(); _ = SetViewDataAsync(); } private async Task SetViewDataAsync() { try { _ = await PublicClientSingleton.Instance.AcquireTokenSilentAsync(); IdTokenClaims = PublicClientSingleton.Instance.MSALClientHelper.AuthResult.ClaimsPrincipal.Claims.Select(c => c.Value); Claims.ItemsSource = IdTokenClaims; } catch (MsalUiRequiredException) { await Shell.Current.GoToAsync("claimsview"); } } protected override bool OnBackButtonPressed() { return true; } private async void SignOutButton_Clicked(object sender, EventArgs e) { await PublicClientSingleton.Instance.SignOutAsync().ContinueWith((t) => { return Task.CompletedTask; }); await Shell.Current.GoToAsync("mainview"); } }
El código ClaimsView.xaml.cs representa el código subyacente de una vista de notificación en una aplicación .NET MAUI. Comienza importando los espacios de nombres necesarios y definiendo la clase
ClaimsView
, que extiendeContentPage
. La propiedadIdTokenClaims
es una enumeración de cadenas, establecida inicialmente en una sola cadena que indica que no se encontraron notificaciones.El constructor
ClaimsView
establece el contexto de enlace en la instancia actual, inicializa los componentes de vista y llama al métodoSetViewDataAsync
de forma asincrónica. El métodoSetViewDataAsync
intenta adquirir un token de forma silenciosa, recupera las notificaciones del resultado de autenticación y establece la propiedadIdTokenClaims
para mostrarlas en elListView
denominadoClaims
. Si se produceMsalUiRequiredException
, lo que indica que la interacción del usuario es necesaria para la autenticación, la aplicación navega a la vista de notificaciones.El método
OnBackButtonPressed
invalida el comportamiento del botón atrás para devolver siempre true, lo que impide que el usuario vuelva de esta vista. El controlador de eventosSignOutButton_Clicked
cierra la sesión del usuario mediante la instanciaPublicClientSingleton
y, al finalizar, navega amain view
.
Modificar el shell de la aplicación
La clase AppShell
define la jerarquía visual de una aplicación, el marcado XAML que se usa para crear la interfaz de usuario de la aplicación. Actualice AppShell
para que sepa sobre Views
.
Haga doble clic en el archivo
AppShell.xaml
del panel Explorador de soluciones para abrir el editor XAML. Reemplace el marcado XAML con el siguiente código:<?xml version="1.0" encoding="UTF-8" ?> <Shell x:Class="SignInMaui.AppShell" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:SignInMaui.Views" Shell.FlyoutBehavior="Disabled"> <ShellContent Title="Home" ContentTemplate="{DataTemplate local:MainView}" Route="MainPage" /> </Shell>
El código XAML define una clase
AppShell
que deshabilita el comportamiento del control flotante y establece el contenido principal en un elementoShellContent
con un títuloHome
y una plantilla de contenido que apunta a la claseMainView
.En el panel Explorador de soluciones de Visual Studio, expanda el archivo AppShell.xaml para mostrar su archivo de código subyacente AppShell.xaml.cs. Abra AppShell.xaml.cs y reemplace el contenido del archivo por el siguiente código:
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using SignInMaui.Views; namespace SignInMaui; public partial class AppShell : Shell { public AppShell() { InitializeComponent(); Routing.RegisterRoute("mainview", typeof(MainView)); Routing.RegisterRoute("claimsview", typeof(ClaimsView)); } }
Actualice el archivo
AppShell.xaml.cs
para incluir los registros de ruta necesarios paraMainView
yClaimsView
. Al llamar al métodoInitializeComponent()
, se garantiza la inicialización de la claseAppShell
. El métodoRegisterRoute()
asocia las rutasmainview
yclaimsview
con sus respectivos tipos de vista,MainView
yClaimsView
.
Agregar código específico de la plataforma
Un proyecto de aplicación de .NET MAUI contiene una carpeta Platforms, con cada carpeta secundaria que representa una plataforma que .NET MAUI puede tener como destino. Para proporcionar un comportamiento específico de la aplicación Android para complementar la clase de aplicación predeterminada, siga estos pasos:
Haga doble clic en el archivo
Platforms/Android/AndroidManifest.xml
en el panel Explorador de soluciones para abrir el editor XML. Actualice las siguientes propiedades:- Establezca el Nombre de aplicación a MAUI CIAM.
- Establezca el Nombre del paquete a SignInMaui.Droid.
- Establezca la Versión mínima de Android a Android 5.0 (nivel de API 21).
Haga doble clic en el archivo
Platforms/Android/MainActivity.cs
en el panel Explorador de soluciones para abrir el editor csharp. Reemplace el contenido del archivo con el siguiente código:// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using Android.App; using Android.Content; using Android.Content.PM; using Android.OS; using SignInMaui.MSALClient; using Microsoft.Identity.Client; namespace SignInMaui; [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] public class MainActivity : MauiAppCompatActivity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // configure platform specific params PlatformConfig.Instance.RedirectUri = $"msal{PublicClientSingleton.Instance.MSALClientHelper.AzureAdConfig.ClientId}://auth"; PlatformConfig.Instance.ParentWindow = this; // Initialize MSAL and platformConfig is set _ = Task.Run(async () => await PublicClientSingleton.Instance.MSALClientHelper.InitializePublicClientAppAsync()).Result; } protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data); } }
Vamos a desglosar las partes clave del código que ha agregado:
- Las instrucciones necesarias
using
se incluyen en la parte superior. - La clase
MainActivity
se define, hereda deMauiAppCompatActivity
, que es la clase base para la plataforma Android en .NET MAUI. - El atributo [Activity] se aplica a la clase
MainActivity
, especificando varias opciones de configuración para la actividad de Android.Theme = "@style/Maui.SplashTheme"
establece el tema de presentación de la actividad.MainLauncher = true
designa esta actividad como el punto de entrada principal de la aplicación.ConfigurationChanges
especifica los cambios de configuración que la actividad puede controlar, como el tamaño de pantalla, la orientación, el modo de interfaz de usuario, el diseño de pantalla, el tamaño de pantalla más pequeño y la densidad.
OnCreate
el método se invalida para proporcionar lógica personalizada cuando se crea la actividad.base.OnCreate(savedInstanceState)
llama a la implementación base del método.PlatformConfig.Instance.RedirectUri
se establece en un valor generado dinámicamente basado enPublicClientSingleton.Instance.MSALClientHelper.AzureAdConfig.ClientId
. Configura el URI de redireccionamiento para el cliente MSAL.PlatformConfig.Instance.ParentWindow
se establece en la instancia de actividad actual, que especifica la ventana primaria para las operaciones relacionadas con la autenticación.PublicClientSingleton.Instance.MSALClientHelper.InitializePublicClientAppAsync()
inicializa la aplicación cliente de MSAL de forma asincrónica mediante un método auxiliar de una instancia singleton denominadaMSALClientHelper
.Task.Run
se usa para ejecutar la inicialización en un subproceso en segundo plano y.Result
se usa para esperar sincrónicamente a que se complete la tarea.
- El método
OnActivityResult
se invalida para controlar el resultado de una actividad iniciada por la actividad actual.base.OnActivityResult(requestCode, resultCode, data)
llama a la implementación base del método.AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data)
establece los argumentos de evento de continuación de autenticación basados en el código de solicitud recibido, el código de resultado y los datos de intención. Se usa para continuar el flujo de autenticación después de que una actividad externa devuelva un resultado.
- Las instrucciones necesarias
En el panel Explorador de soluciones de Visual Studio, seleccione Plataformas.
Haga clic con el botón derecho en la carpeta Android>Agregar>Nuevo elemento....
Seleccione Clase de elementos>de C#. Ponga al archivo el nombre
MsalActivity.cs
.Reemplace el contenido del archivo
MsalActivity.cs
por el siguiente código:// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; using Android.Widget; using Microsoft.Identity.Client; namespace MauiAppBasic.Platforms.Android.Resources { [Activity(Exported =true)] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataHost = "auth", DataScheme = "msalEnter_the_Application_Id_Here")] public class MsalActivity : BrowserTabActivity { } }
Vamos a desglosar las partes clave del código que ha agregado:
- La clase
MsalActivity
se declara dentro del espacio de nombresMauiAppBasic.Platforms.Android.Resources
. La clase hereda de la claseBrowserTabActivity
, lo que indica que amplía su funcionalidad. - La clase está decorada con el atributo
[Activity(Exported = true)]
, lo que significa que la actividad se exporta y se puede tener acceso a ella mediante otros métodos. - Se especifica un filtro de intención mediante el atributo "[IntentFilter(...)]". Configura la actividad para interceptar la intención
ActionView
. - El filtro de intención se establece para controlar la intención
ActionView
con el especificadoDataScheme
(msalEnter_the_Application_Id_Here
) yDataHost
("autenticación"). Esta configuración permite que la actividad controle el proceso de autenticación interceptando y procesando la intenciónActionView
. ReemplaceEnter_the_Application_Id_Here
por el Id. de aplicación (cliente) de la aplicación que registró anteriormente.
- La clase
Agregar la configuración de la aplicación
La configuración permite la separación de datos que configura el comportamiento de una aplicación desde el código, lo que permite cambiar el comportamiento sin volver a generar la aplicación. MauiAppBuilder
proporciona ConfigurationManager
para configurar las opciones en nuestra aplicación .NET MAUI. Vamos a agregar el archivo appsettings.json
como EmbeddedResource
.
Siga estos pasos para crear appsettings.json
:
En el panel Explorador de soluciones de Visual Studio, haga clic con el botón derecho en el proyecto SignInMaui>Agregar>Nuevo elemento....
Seleccione Web>Archivo de configuración JSON de JavaScript. Ponga al archivo el nombre
appsettings.json
.Seleccione Agregar.
Seleccione appsettings.json
En el panel Propiedades, establezca Acción de compilación en Recurso incrustado.
En el panel Propiedades, establezca Copiar en el directorio de salida en Copiar si es posterior.
Reemplace el contenido del archivo
appsettings.json
por el siguiente código:{ "AzureAd": { "Authority": "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/", "ClientId": "Enter_the_Application_Id_Here", "CacheFileName": "msal_cache.txt", "CacheDir": "C:/temp" }, "DownstreamApi": { "Scopes": "openid offline_access" } }
En
appsettings.json
, busque el marcador de posición:Enter_the_Tenant_Subdomain_Here
y reemplácelo por el subdominio del directorio (inquilino). Por ejemplo, si el dominio principal del inquilino escontoso.onmicrosoft.com
, usecontoso
. Si no tiene el nombre del inquilino, vea cómo leer los datos del inquilino.Enter_the_Application_Id_Here
y reemplácelo por el identificador de aplicación (cliente) de la aplicación que registró anteriormente.
Uso del dominio de dirección URL personalizado (opcional)
Use un dominio personalizado para personalizar completamente la dirección URL de autenticación. Desde el punto de vista del usuario, este permanece en el dominio durante el proceso de autenticación, en lugar de que se le redirija al nombre de dominio ciamlogin.com.
Siga estos pasos para usar un dominio personalizado:
Siga los pasos descritos en Habilitar dominios de dirección URL personalizados para aplicaciones en inquilinos externos para habilitar la dirección URL de dominio personalizado para el inquilino externo.
Abra el archivo appsettings.json:
- Actualice el valor de la propiedad
Authority
a https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here. ReemplaceEnter_the_Custom_Domain_Here
por la dirección URL de dominio personalizado yEnter_the_Tenant_ID_Here
por el identificador del inquilino. Si no tiene el identificador del inquilino, obtenga información sobre cómo leer los detalles del inquilino. - Agregue la propiedad
knownAuthorities
con un valor [Escriba_aquí_el_dominio_personalizado].
- Actualice el valor de la propiedad
Después de realizar los cambios en el archivo appsettings.json, si la dirección URL del dominio personalizado es login.contoso.com y el identificador de inquilino es aaaabbbb-0000-cccc-1111-dddd2222eeee, el archivo deberá tener un aspecto similar al siguiente fragmento de código:
{
"AzureAd": {
"Authority": "https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee",
"ClientId": "Enter_the_Application_Id_Here",
"CacheFileName": "msal_cache.txt",
"CacheDir": "C:/temp",
"KnownAuthorities": ["login.contoso.com"]
},
"DownstreamApi": {
"Scopes": "openid offline_access"
}
}
Ejecución y prueba de la aplicación móvil .NET MAUI
Las aplicaciones .NET MAUI están diseñadas para ejecutarse en varios sistemas operativos y dispositivos. Deberá seleccionar el destino con el que quiere probar y depurar la aplicación.
Establezca el Destino de depuración en la barra de herramientas de Visual Studio en el dispositivo con el que desea depurar y probar. En los siguientes pasos se muestra cómo establecer el Destino de depuración en Android:
- Seleccione Destino de depuración de la lista desplegable.
- Seleccione Android Emulators.
- Seleccione el dispositivo del emulador.
Ejecute la aplicación presionando F5 o seleccionando el botón reproducir situado en la parte superior de Visual Studio.
Ahora puede probar la aplicación .NET MAUI de Android de ejemplo. Después de ejecutar la aplicación, la ventana de la aplicación de Android aparece en un emulador:
En la ventana de Android que aparece, seleccione el botón Iniciar sesión. Se abre una ventana del explorador y se le pide que inicie sesión.
Durante el proceso de inicio de sesión, se le pedirá que conceda varios permisos (para permitir que la aplicación acceda a los datos). Tras iniciar sesión y dar su consentimiento correctamente, la pantalla de la aplicación muestra la página principal.