Autenticación de usuarios con Azure Active Directory B2C
Azure Active Directory B2C proporciona administración de identidades en la nube destinada a aplicaciones móviles y web orientadas al consumidor. En este artículo se muestra cómo usar Azure Active Directory B2C para integrar la administración de identidades en una aplicación para dispositivos móviles con la Biblioteca de autenticación de Microsoft.
Información general
Azure Active Directory B2C (ADB2C) es un servicio de administración de identidades para aplicaciones orientadas al consumidor. Permite a los usuarios iniciar sesión en la aplicación con sus cuentas sociales existentes o credenciales personalizadas, como el correo electrónico o el nombre de usuario y la contraseña. Las cuentas de credenciales personalizadas se conocen como cuentas locales.
El proceso para integrar el servicio de administración de identidades de Azure Active Directory B2C en una aplicación móvil es el siguiente:
- Crear un inquilino de Azure Active Directory B2C.
- Registre la aplicación móvil con el inquilino de Azure Active Directory B2C.
- Cree directivas para flujos de usuario de registro, inicio de sesión y contraseña olvidada.
- Use la Biblioteca de autenticación de Microsoft (MSAL) para iniciar un flujo de trabajo de autenticación con el inquilino de Azure Active Directory B2C.
Nota:
Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.
Azure Active Directory B2C admite varios proveedores de identidades, como Microsoft, GitHub, Facebook, Twitter y mucho más. Para más información sobre las funcionalidades de Azure Active Directory B2C, vea Documentación de Azure Active Directory B2C.
La biblioteca de autenticación de Microsoft admite varias plataformas y arquitecturas de aplicaciones. Para obtener información sobre las funcionalidades de MSAL, vea Biblioteca de autenticación de Microsoft en GitHub.
Configuración de un inquilino de Azure Active Directory B2C
Para ejecutar el proyecto de ejemplo, debe crear un inquilino de Azure Active Directory B2C. Para más información, vea Creación de un inquilino de Azure Active Directory B2C en Azure Portal.
Una vez que cree un inquilino, necesitará el nombre del inquilino y el identificador de inquilino para configurar la aplicación móvil. El identificador y el nombre del inquilino se definen mediante el dominio generado al crear la dirección URL del inquilino. Si la dirección URL del inquilino generada es https://contoso20190410tenant.onmicrosoft.com/
, el identificador de inquilino es contoso20190410tenant.onmicrosoft.com
y el nombre del inquilino es contoso20190410tenant
. Busque el dominio de inquilino en Azure Portal; para ello, haga clic en el filtro de directorio y suscripción en el menú superior. En la captura de pantalla siguiente se muestra el botón de filtro de directorio y suscripción de Azure y el dominio de inquilino:
En el proyecto de ejemplo, edite el archivo Constants.cs para establecer los campos tenantName
y tenantId
. En el código siguiente se muestra cómo se deben establecer estos valores si el dominio de inquilino es https://contoso20190410tenant.onmicrosoft.com/
; reemplace estos valores por valores del portal:
public static class Constants
{
static readonly string tenantName = "contoso20190410tenant";
static readonly string tenantId = "contoso20190410tenant.onmicrosoft.com";
...
}
Registro de la aplicación móvil con Azure Active Directory B2C
Una aplicación móvil se debe registrar con el inquilino para poder conectarse y autenticar a los usuarios. El proceso de registro asigna un id. de aplicación único a la aplicación y una URL de redireccionamiento que dirige las respuestas a la aplicación después de la autenticación. Para más información, vea Azure Active Directory B2C: Registro de la aplicación. Deberá conocer el id. de aplicación asignado a la aplicación, que aparece después del nombre de la aplicación en la vista de propiedades. En la captura de pantalla siguiente se muestra dónde encontrar el id. de aplicación:
La biblioteca de autenticación de Microsoft espera que la URL de redireccionamiento de la aplicación sea el id. de aplicación con el texto "msal" como prefijo y seguido de un punto de conexión denominado "auth". Si el id. de aplicación es "1234abcd", la dirección URL completa debe ser msal1234abcd://auth
. Asegúrese de que la aplicación ha habilitado el valor Cliente nativo y cree un URI de redireccionamiento personalizado mediante el id. de aplicación, como se muestra en la captura de pantalla siguiente:
La dirección URL se usará más adelante en el archivo ApplicationManifest.xml de Android y en el archivo Info.plist de iOS.
En el proyecto de ejemplo, edite el archivo Constants.cs para establecer el campo clientId
en el id. de aplicación. En el código siguiente se muestra cómo se debe establecer este valor si el id. de aplicación es 1234abcd
:
public static class Constants
{
static readonly string tenantName = "contoso20190410tenant";
static readonly string tenantId = "contoso20190410tenant.onmicrosoft.com";
static readonly string clientId = "1234abcd";
...
}
Creación de directivas de registro e inicio de sesión, y directivas de contraseña olvidada
Una directiva es una experiencia por la que pasan los usuarios para completar una tarea como crear una cuenta o restablecer una contraseña. Una directiva también especifica el contenido de los tokens que recibe la aplicación cuando el usuario vuelve de la experiencia. Debe configurar directivas para el registro y el inicio de sesión de la cuenta, así como para restablecer la contraseña. Azure tiene directivas integradas que simplifican la creación de directivas comunes. Para más información, vea Azure Active Directory B2C: directivas integradas.
Cuando haya completado la configuración de directivas, debe tener dos directivas en la vista Flujos de usuario (directivas) en Azure Portal. En la captura de pantalla siguiente se muestran dos directivas configuradas en Azure Portal:
En el proyecto de ejemplo, edite el archivo Constants.cs a fin de establecer los campos policySignin
y policyPassword
para reflejar los nombres que haya elegido durante la configuración de las directivas:
public static class Constants
{
static readonly string tenantName = "contoso20190410tenant";
static readonly string tenantId = "contoso20190410tenant.onmicrosoft.com";
static readonly string clientId = "1234abcd";
static readonly string policySignin = "B2C_1_signupsignin1";
static readonly string policyPassword = "B2C_1_passwordreset";
...
}
Uso de la biblioteca de autenticación de Microsoft (MSAL) para la autenticación
El paquete NuGet de la Biblioteca de autenticación de Microsoft (MSAL) se debe agregar al proyecto de .NET Standard compartido y a los proyectos de plataforma de una solución de Xamarin.Forms. MSAL incluye una clase PublicClientApplicationBuilder
que construye un objeto que se adhiere a la interfaz IPublicClientApplication
. MSAL utiliza cláusulas With
para proporcionar parámetros adicionales al constructor y a los métodos de autenticación.
En el proyecto de ejemplo, el código subyacente para App.xaml define las propiedades estáticas denominadas AuthenticationClient
y UIParent
, y crea instancias del objeto AuthenticationClient
en el constructor. La cláusula WithIosKeychainSecurityGroup
proporciona un nombre de grupo de seguridad para aplicaciones iOS. La cláusula WithB2CAuthority
proporciona la entidad predeterminada, o directiva, que se usará para autenticar a los usuarios. La cláusula WithRedirectUri
indica a la instancia de Azure Notification Hubs qué URI de redireccionamiento se va a usar si se especifican varios URI. En el ejemplo siguiente se muestra cómo crear una instancia de PublicClientApplication
:
public partial class App : Application
{
public static IPublicClientApplication AuthenticationClient { get; private set; }
public static object UIParent { get; set; } = null;
public App()
{
InitializeComponent();
AuthenticationClient = PublicClientApplicationBuilder.Create(Constants.ClientId)
.WithIosKeychainSecurityGroup(Constants.IosKeychainSecurityGroups)
.WithB2CAuthority(Constants.AuthoritySignin)
.WithRedirectUri($"msal{Constants.ClientId}://auth")
.Build();
MainPage = new NavigationPage(new LoginPage());
}
...
Nota:
Si la instancia de Azure Notification Hubs solo tiene definido un URI de redireccionamiento, la instancia de AuthenticationClient
puede funcionar sin especificar el URI de redireccionamiento con la cláusula WithRedirectUri
. Pero siempre debe especificar este valor en caso de que la configuración de Azure se expanda para admitir otros clientes o métodos de autenticación.
El controlador de eventos OnAppearing
del código subyacente de LoginPage.xaml.cs llama a AcquireTokenSilentAsync
a fin de actualizar el token de autenticación para los usuarios que han iniciado sesión antes. El proceso de autenticación se redirige a LogoutPage
si es correcto y no hace nada en caso de error. En el ejemplo siguiente se muestra el proceso de reautenticación silenciosa en OnAppearing
:
public partial class LoginPage : ContentPage
{
...
protected override async void OnAppearing()
{
try
{
// Look for existing account
IEnumerable<IAccount> accounts = await App.AuthenticationClient.GetAccountsAsync();
AuthenticationResult result = await App.AuthenticationClient
.AcquireTokenSilent(Constants.Scopes, accounts.FirstOrDefault())
.ExecuteAsync();
await Navigation.PushAsync(new LogoutPage(result));
}
catch
{
// Do nothing - the user isn't logged in
}
base.OnAppearing();
}
...
}
El controlador de eventos OnLoginButtonClicked
(desencadenado cuando se hace clic en el botón Inicio de sesión) llama a AcquireTokenAsync
. La biblioteca MSAL abre automáticamente el explorador del dispositivo móvil y navega a la página de inicio de sesión. La dirección URL de inicio de sesión, denominada Autoridad, es una combinación del nombre de inquilino y las directivas definidas en el archivo Constants.cs. Si el usuario elige la opción de contraseña olvidada, vuelve a la aplicación con una excepción, lo que inicia la experiencia de contraseña olvidada. En el ejemplo siguiente se muestra el proceso de autenticación:
public partial class LoginPage : ContentPage
{
...
async void OnLoginButtonClicked(object sender, EventArgs e)
{
AuthenticationResult result;
try
{
result = await App.AuthenticationClient
.AcquireTokenInteractive(Constants.Scopes)
.WithPrompt(Prompt.SelectAccount)
.WithParentActivityOrWindow(App.UIParent)
.ExecuteAsync();
await Navigation.PushAsync(new LogoutPage(result));
}
catch (MsalException ex)
{
if (ex.Message != null && ex.Message.Contains("AADB2C90118"))
{
result = await OnForgotPassword();
await Navigation.PushAsync(new LogoutPage(result));
}
else if (ex.ErrorCode != "authentication_canceled")
{
await DisplayAlert("An error has occurred", "Exception message: " + ex.Message, "Dismiss");
}
}
}
...
}
El método OnForgotPassword
es similar al proceso de inicio de sesión, pero implementa una directiva personalizada. OnForgotPassword
usa otra sobrecarga de AcquireTokenAsync
, que permite proporcionar una autoridad específica. En el ejemplo siguiente se muestra cómo proporcionar una autoridad personalizada al adquirir un token:
public partial class LoginPage : ContentPage
{
...
async Task<AuthenticationResult> OnForgotPassword()
{
try
{
return await App.AuthenticationClient
.AcquireTokenInteractive(Constants.Scopes)
.WithPrompt(Prompt.SelectAccount)
.WithParentActivityOrWindow(App.UIParent)
.WithB2CAuthority(Constants.AuthorityPasswordReset)
.ExecuteAsync();
}
catch (MsalException)
{
// Do nothing - ErrorCode will be displayed in OnLoginButtonClicked
return null;
}
}
}
La última parte de la autenticación es el proceso de cierre de sesión. Se llama al método OnLogoutButtonClicked
cuando el usuario presiona el botón de cierre de sesión. Recorre en bucle todas las cuentas y garantiza que sus tokens se han invalidado. En el ejemplo siguiente se muestra la implementación del cierre de sesión:
public partial class LogoutPage : ContentPage
{
...
async void OnLogoutButtonClicked(object sender, EventArgs e)
{
IEnumerable<IAccount> accounts = await App.AuthenticationClient.GetAccountsAsync();
while (accounts.Any())
{
await App.AuthenticationClient.RemoveAsync(accounts.First());
accounts = await App.AuthenticationClient.GetAccountsAsync();
}
await Navigation.PopAsync();
}
}
iOS
En iOS, el esquema de dirección URL personalizado que se ha registrado con Azure Active Directory B2C se debe registrar en Info.plist. MSAL espera que el esquema de dirección URL se ajuste a un patrón específico, descrito anteriormente en Registro de la aplicación móvil con Azure Active Directory B2C. En la captura de pantalla siguiente se muestra el esquema de dirección URL personalizado en Info.plist.
MSAL también exige Derechos de cadena de claves en iOS, registrados en Entitilements.plist, como se muestra en la captura de pantalla siguiente:
Cuando Azure Active Directory B2C completa la solicitud de autorización, realiza el redireccionamiento a la dirección URL de redireccionamiento registrada. El esquema de dirección URL personalizada da como resultado que iOS inicie la aplicación móvil y pase la URL como parámetro de inicio, donde se procesa mediante la invalidación OpenUrl
de la clase AppDelegate
de la aplicación y devuelve el control de la experiencia a MSAL. La implementación de OpenUrl
se muestra en el ejemplo de código siguiente:
using Microsoft.Identity.Client;
namespace TodoAzure.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
...
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(url);
return base.OpenUrl(app, url, options);
}
}
}
Android
En Android, el esquema de dirección URL personalizado que se ha registrado con Azure Active Directory B2C se debe registrar en AndroidManifest.xml. MSAL espera que el esquema de dirección URL se ajuste a un patrón específico, descrito anteriormente en Registro de la aplicación móvil con Azure Active Directory B2C. En el ejemplo siguiente se muestra el esquema de dirección URL personalizado en AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.adb2cauthorization">
<uses-sdk android:minSdkVersion="15" />
<application android:label="ADB2CAuthorization">
<activity android:name="microsoft.identity.client.BrowserTabActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- example -->
<!-- <data android:scheme="msalaaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" android:host="auth" /> -->
<data android:scheme="INSERT_URI_SCHEME_HERE" android:host="auth" />
</intent-filter>
</activity>"
</application>
</manifest>
La clase MainActivity
se debe modificar para proporcionar el objeto UIParent
a la aplicación durante la llamada a OnCreate
. Cuando Azure Active Directory B2C completa la solicitud de autorización, realiza el redireccionamiento al esquema de dirección URL registrado desde AndroidManifest.xml. El esquema de URI registrado da como resultado que Android llame al método OnActivityResult
con la dirección URL como parámetro de inicio, donde la procesa el método SetAuthenticationContinuationEventArgs
.
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Forms.Init(this, bundle);
LoadApplication(new App());
App.UIParent = this;
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
AuthenticationContinuationHelper.SetAuthenticationContinuationEventArgs(requestCode, resultCode, data);
}
}
Plataforma universal de Windows
No se necesita ninguna configuración adicional para usar MSAL en la Plataforma universal de Windows
Ejecución del proyecto
Ejecute la aplicación en un dispositivo virtual o físico. Al pulsar el botón Iniciar sesión se debe abrir el explorador y navegar a una página donde se puede iniciar sesión o crear una cuenta. Después de completar el proceso de inicio de sesión, debe volver a la página de cierre de sesión de la aplicación. En la captura de pantalla siguiente se muestra la pantalla de inicio de sesión del usuario en ejecución en Android e iOS: