Habilitación de la autenticación en una aplicación de Android propia mediante Azure AD B2C
En este artículo se muestra cómo agregar la autenticación de Azure Active Directory B2C (Azure AD B2C) a su propia aplicación móvil Android.
Use este artículo con Configuración de la autenticación en una aplicación Android de ejemplo mediante Azure AD B2C y sustituya la aplicación Android de ejemplo por la suya propia. Después de completar las instrucciones de este artículo, la aplicación aceptará inicios de sesión mediante Azure AD B2C.
Requisitos previos
Revise los requisitos previos y las instrucciones de integración de Configuración de la autenticación en una aplicación Android de ejemplo mediante Azure AD B2C.
Creación de un proyecto de aplicación Android
Si aún no tiene una aplicación Android, haga lo siguiente para configurar un nuevo proyecto:
- En Android Studio, seleccione Start a new Android Studio project (Iniciar un proyecto de Android Studio).
- Seleccione Basic Activity (Actividad básica) y, después, Siguiente.
- Asigne un nombre a la aplicación.
- Guarde el nombre del paquete. Deberá escribirlo más tarde en Azure Portal.
- Cambie el lenguaje de Kotlin a Java.
- Establezca el nivel de API mínimo en API 19 o superior y seleccione Finalizar.
- En la vista de proyecto, seleccione Proyecto en la lista desplegable para mostrar los archivos de proyecto de origen y que no sean de origen, abra app/build.gradle y, después, establezca targetSdkVersion en 28.
Paso 1: Instalación de las dependencias
En la ventana del proyecto de Android Studio, vaya a app>build.gradle y, después, agregue lo siguiente:
apply plugin: 'com.android.application'
allprojects {
repositories {
mavenCentral()
google()
mavenLocal()
maven {
url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1'
}
maven {
name "vsts-maven-adal-android"
url "https://identitydivision.pkgs.visualstudio.com/_packaging/AndroidADAL/maven/v1"
credentials {
username System.getenv("ENV_VSTS_MVN_ANDROIDADAL_USERNAME") != null ? System.getenv("ENV_VSTS_MVN_ANDROIDADAL_USERNAME") : project.findProperty("vstsUsername")
password System.getenv("ENV_VSTS_MVN_ANDROIDADAL_ACCESSTOKEN") != null ? System.getenv("ENV_VSTS_MVN_ANDROIDADAL_ACCESSTOKEN") : project.findProperty("vstsMavenAccessToken")
}
}
jcenter()
}
}
dependencies{
implementation 'com.microsoft.identity.client:msal:2.+'
}
packagingOptions{
exclude("META-INF/jersey-module-version")
}
Paso 2: Adición de componentes de autenticación
El código de ejemplo consta de los siguientes componentes. Agregue estos componentes de la aplicación Android de ejemplo a su propia aplicación.
Componente | Tipo | Source | Descripción |
---|---|---|---|
B2CUser | Clase | Kotlin Java | Representa un usuario B2C. Esta clase permite a los usuarios iniciar sesión con varias directivas. |
B2CModeFragment | Clase de fragmento | Kotlin Java | Un fragmento representa una parte modular del inicio de sesión con la interfaz de usuario de Azure AD B2C dentro de la actividad principal. Este fragmento contiene la mayor parte del código de autenticación. |
fragment_b2c_mode.xml | Diseño de fragmentos | Kotlin Java | Define la estructura de una interfaz de usuario para el componente de fragmento B2CModeFragment. |
B2CConfiguration | Clase | Kotlin Java | Un archivo de configuración contiene información sobre el proveedor de identidades de Azure AD B2C. La aplicación móvil usa esta información para establecer una relación de confianza con Azure AD B2C, iniciar y cerrar la sesión de los usuarios y obtener tokens y validarlos. Para más opciones de configuración, consulte el archivo auth_config_b2c.json. |
auth_config_b2c.json | Archivo JSON | Kotlin Java | Un archivo de configuración contiene información sobre el proveedor de identidades de Azure AD B2C. La aplicación móvil usa esta información para establecer una relación de confianza con Azure AD B2C, iniciar y cerrar la sesión de los usuarios y obtener tokens y validarlos. Para obtener más opciones de configuración, vea la clase B2CConfiguration. |
Paso 3: Configuración de su aplicación para Android
Después de agregar los componentes de autenticación, configure la aplicación Android con los ajustes de Azure AD B2C. Los ajustes del proveedor de identidad de Azure AD B2C se configuran en el archivo auth_config_b2c.json y en la clase B2CConfiguration.
Para obtener más información, consulte Configuración de la aplicación móvil de ejemplo.
Paso 4: Establecimiento del URI de redireccionamiento
Configure dónde escucha su aplicación la respuesta del token de Azure AD B2C.
Genere un nuevo hash de firma de desarrollo. Esto cambiará para cada entorno de desarrollo.
Para Windows:
keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64
Para iOS:
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
Para un entorno de producción, use el siguiente comando:
keytool -exportcert -alias SIGNATURE_ALIAS -keystore PATH_TO_KEYSTORE | openssl sha1 -binary | openssl base64
Para obtener más ayuda con la firma de sus aplicaciones, consulte Firma de su aplicación Android.
Seleccione app>src>main>AndroidManifest.xml y, después, agregue la siguiente actividad
BrowserTabActivity
al cuerpo de la aplicación:<!--Intent filter to capture System Browser or Authenticator calling back to our app after sign-in--> <activity android:name="com.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" /> <data android:scheme="msauth" android:host="Package_Name" android:path="/Signature_Hash" /> </intent-filter> </activity>
Sustituya
Signature_Hash
por el hash que ha generado.Sustituya
Package_Name
por el nombre de su paquete Android.
Para actualizar el registro de la aplicación móvil con el URI de redireccionamiento de la aplicación, haga lo siguiente:
- Inicie sesión en Azure Portal.
- Si tiene acceso a varios inquilinos, seleccione el icono Configuración en el menú superior para cambiar a su inquilino de Azure AD B2C desde el menú Directorios y suscripciones.
- Busque y seleccione Azure AD B2C.
- Seleccione Registros de aplicaciones y, después, seleccione la aplicación que registró en el Paso 2.3: Registro de la aplicación móvil.
- Seleccione Autenticación.
- En Android, seleccione Agregar URI.
- Escriba el Nombre del paquete y el Hash de firma.
- Seleccione Guardar.
El URI de redirección y la actividad BrowserTabActivity
deben ser similares al ejemplo siguiente:
La dirección URL de redireccionamiento del ejemplo de Android se ve así:
msauth://com.azuresamples.msalandroidkotlinapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D
El filtro de intención usa el mismo patrón, como se muestra en el siguiente fragmento XML:
<activity android:name="com.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" />
<data
android:host="com.azuresamples.msalandroidkotlinapp"
android:path="/1wIqXSqBj7w+h11ZifsnqwgyKrY="
android:scheme="msauth" />
</intent-filter>
</activity>
Paso 5: Personalización de los bloques de compilación de código
En esta sección se describen los bloques de compilación de código que habilitan la autenticación para la aplicación Android. En la tabla siguiente se enumeran los métodos de B2CModeFragment y se explica cómo personalizar el código.
Paso 5.1: Creación de instancias de una aplicación cliente pública
Las aplicaciones cliente públicas no son de confianza para mantener los secretos de aplicación de forma segura y no tienen secretos de cliente. En onCreate u onCreateView, cree una instancia de MSAL mediante el objeto de aplicación de cliente pública de varias cuentas.
La clase MultipleAccountPublicClientApplication
se usa para crear aplicaciones basadas en MSAL que permitan que varias cuentas inicien sesión al mismo tiempo. La clase permite el inicio de sesión con varios flujos de usuario de Azure AD B2C o directivas personalizadas. Por ejemplo, los usuarios inician sesión con un flujo de usuario de registro o inicio de sesión y, posteriormente, ejecutan un flujo de usuario de edición de perfil.
El siguiente fragmento de código muestra cómo inicializar la biblioteca MSAL con un archivo JSON de configuración auth_config_b2c.json
.
PublicClientApplication.createMultipleAccountPublicClientApplication(context!!,
R.raw.auth_config_b2c,
object : IMultipleAccountApplicationCreatedListener {
override fun onCreated(application: IMultipleAccountPublicClientApplication) {
// Set the MultipleAccountPublicClientApplication to the class member b2cApp
b2cApp = application
// Load the account (if there is any)
loadAccounts()
}
override fun onError(exception: MsalException) {
// Error handling
displayError(exception)
}
})
Paso 5.2: Carga de cuentas
Cuando la aplicación llega al primer plano, carga la cuenta existente para determinar si los usuarios han iniciado sesión. Use este método para actualizar la interfaz de usuario con el estado de autenticación. Por ejemplo, puede habilitar o deshabilitar el botón de cierre de sesión.
El siguiente fragmento de código muestra cómo cargar las cuentas.
private fun loadAccounts() {
if (b2cApp == null) {
return
}
b2cApp!!.getAccounts(object : LoadAccountsCallback {
override fun onTaskCompleted(result: List<IAccount>) {
users = B2CUser.getB2CUsersFromAccountList(result)
updateUI(users)
}
override fun onError(exception: MsalException) {
displayError(exception)
}
})
}
Paso 5.3: Inicio de una solicitud de autorización interactiva
Una solicitud de autorización interactiva es un flujo en el que se solicita a los usuarios que se registren o inicien sesión. El método initializeUI
configura el evento de clic runUserFlowButton
. Cuando los usuarios seleccionan el botón Ejecutar flujo de usuario, la aplicación los lleva a Azure AD B2C para completar el flujo de inicio de sesión.
El método runUserFlowButton.setOnClickListener
prepara el objeto AcquireTokenParameters
con datos relevantes sobre la solicitud de autorización. Después, el método acquireToken
solicita a los usuarios que completen el flujo de registro o de inicio de sesión.
El siguiente fragmento de código muestra cómo iniciar la solicitud de autorización interactiva:
val parameters = AcquireTokenParameters.Builder()
.startAuthorizationFromActivity(activity)
.fromAuthority(getAuthorityFromPolicyName(policy_list.getSelectedItem().toString()))
.withScopes(B2CConfiguration.scopes)
.withPrompt(Prompt.LOGIN)
.withCallback(authInteractiveCallback)
.build()
b2cApp!!.acquireToken(parameters)
Paso 5.4: Llamada de solicitud de autorización interactiva
Una vez que los usuarios finalizan el flujo de autorización, ya se de forma correcta o incorrecta, el resultado se devuelve al método de devolución de llamada getAuthInteractiveCallback()
.
El método de devolución de llamada pasa el objeto AuthenticationResult
, o un mensaje de error en el objeto MsalException
. Use este método para:
- Actualizar la interfaz de usuario de la aplicación móvil con información una vez terminado el inicio de sesión.
- Recargar el objeto de cuentas.
- Llame a un servicio de API web con un token de acceso.
- Controlar errores de autenticación.
El siguiente fragmento de código muestra el uso de la devolución de llamada de autenticación interactiva.
private val authInteractiveCallback: AuthenticationCallback
private get() = object : AuthenticationCallback {
override fun onSuccess(authenticationResult: IAuthenticationResult) {
/* Successfully got a token, use it to call a protected resource; web API */
Log.d(TAG, "Successfully authenticated")
/* display result info */
displayResult(authenticationResult)
/* Reload account asynchronously to get the up-to-date list. */
loadAccounts()
}
override fun onError(exception: MsalException) {
val B2C_PASSWORD_CHANGE = "AADB2C90118"
if (exception.message!!.contains(B2C_PASSWORD_CHANGE)) {
txt_log!!.text = """
Users click the 'Forgot Password' link in a sign-up or sign-in user flow.
Your application needs to handle this error code by running a specific user flow that resets the password.
""".trimIndent()
return
}
/* Failed to acquireToken */Log.d(TAG, "Authentication failed: $exception")
displayError(exception)
if (exception is MsalClientException) {
/* Exception inside MSAL, more info inside MsalError.java */
} else if (exception is MsalServiceException) {
/* Exception when communicating with the STS, likely config issue */
}
}
override fun onCancel() {
/* User canceled the authentication */
Log.d(TAG, "User cancelled login.")
}
}
Paso 6: Llamada a una API web
Para llamar a una API web de autorización basada en tokens, la aplicación necesita un token de acceso válido. La aplicación hace lo siguiente:
- Adquiere un token de acceso con los permisos necesarios (ámbitos) para el punto de conexión de API web.
- Pasa el token de acceso como token de portador en el encabezado de autorización de la solicitud HTTP con este formato:
Authorization: Bearer <access-token>
Cuando los usuarios inician sesión interactivamente, la aplicación obtiene un token de acceso en el método de devolución de llamada getAuthInteractiveCallback
. Para las llamadas consecutivas a la API web, utilice el procedimiento silencioso de adquisición de tokens tal y como se describe en esta sección.
Antes de llamar a una API web, llame al método acquireTokenSilentAsync
con los ámbitos adecuados para el punto de conexión de la API web. La biblioteca MSAL hace lo siguiente:
- Intenta capturar un token de acceso con los ámbitos solicitados de la caché de tokens. Si el token está presente, se devuelve.
- Si el token no está presente en la caché de tokens, MSAL intenta usar su token de actualización para adquirir un nuevo token.
- Si el token de actualización no existe o ha expirado, se devuelve una excepción. Recomendamos que pida al usuario que inicie sesión de forma interactiva.
El fragmento de código siguiente muestra cómo adquirir un token de acceso:
El evento de clic del botón acquireTokenSilentButton
adquiere un token de acceso con los ámbitos proporcionados.
btn_acquireTokenSilently.setOnClickListener(View.OnClickListener {
if (b2cApp == null) {
return@OnClickListener
}
val selectedUser = users!![user_list.getSelectedItemPosition()]
selectedUser.acquireTokenSilentAsync(b2cApp!!,
policy_list.getSelectedItem().toString(),
B2CConfiguration.scopes,
authSilentCallback)
})
El método de devolución de llamada authSilentCallback
devuelve un token de acceso y llama a una API web:
private val authSilentCallback: SilentAuthenticationCallback
private get() = object : SilentAuthenticationCallback {
override fun onSuccess(authenticationResult: IAuthenticationResult) {
Log.d(TAG, "Successfully authenticated")
/* Call your web API here*/
callWebAPI(authenticationResult)
}
override fun onError(exception: MsalException) {
/* Failed to acquireToken */
Log.d(TAG, "Authentication failed: $exception")
displayError(exception)
if (exception is MsalClientException) {
/* Exception inside MSAL, more info inside MsalError.java */
} else if (exception is MsalServiceException) {
/* Exception when communicating with the STS, likely config issue */
} else if (exception is MsalUiRequiredException) {
/* Tokens expired or no session, retry with interactive */
}
}
}
El ejemplo siguiente se demuestra cómo llamar a una API web protegida con un token de portador:
@Throws(java.lang.Exception::class)
private fun callWebAPI(authenticationResult: IAuthenticationResult) {
val accessToken = authenticationResult.accessToken
val thread = Thread {
try {
val url = URL("https://your-app-service.azurewebsites.net/helo")
val conn = url.openConnection() as HttpsURLConnection
conn.setRequestProperty("Accept", "application/json")
// Set the bearer token
conn.setRequestProperty("Authorization", "Bearer $accessToken")
if (conn.responseCode == HttpURLConnection.HTTP_OK) {
val br = BufferedReader(InputStreamReader(conn.inputStream))
var strCurrentLine: String?
while (br.readLine().also { strCurrentLine = it } != null) {
Log.d(TAG, strCurrentLine)
}
}
conn.disconnect()
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
}
thread.start()
}
Adición de permiso para realizar operaciones de red
Para realizar operaciones de red en la aplicación, agregue el siguiente permiso para el manifiesto. Para obtener más información, consulte Cómo conectarse a la red.
<uses-permission android:name="android.permission.INTERNET"/>
Pasos siguientes
Obtenga información sobre cómo: