Abilitare l'autenticazione nella propria app Android usando Azure AD B2C

Questo articolo illustra come aggiungere l'autenticazione di Azure Active Directory B2C (Azure AD B2C) alla propria applicazione per dispositivi mobili Android.

Usare questo articolo con Configurare l'autenticazione in un'app Android di esempio usando Azure AD B2C, sostituendo l'app Android di esempio con la propria app Android. Dopo aver completato le istruzioni in questo articolo, l'applicazione accetterà gli accessi tramite Azure AD B2C.

Prerequisiti

Esaminare i prerequisiti e le istruzioni di integrazione in Configurare l'autenticazione in un'app Android di esempio usando Azure AD B2C.

Creare un progetto di app Android

Se non si ha già un'applicazione Android, configurare un nuovo progetto eseguendo le operazioni seguenti:

  1. In Android Studio selezionare Start a new Android Studio project (Avvia un nuovo progetto Android Studio).
  2. Selezionare Attività di base e quindi avanti.
  3. Assegnare un nome all'applicazione.
  4. Salvare il nome del pacchetto. Verrà immesso più avanti nella portale di Azure.
  5. Modificare il linguaggio da Kotlin a Java.
  6. Impostare Il livello API minimo su API 19 o versione successiva e quindi selezionare Fine.
  7. Nella visualizzazione progetto scegliere Progetto nell'elenco a discesa per visualizzare i file di progetto di origine e non di origine, aprire app/build.gradle e quindi impostare targetSdkVersion su 28.

Passaggio 1: Installare le dipendenze

Nella finestra del progetto Android Studio passare ad app>build.gradle e quindi aggiungere quanto segue:

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")
}

Passaggio 2: Aggiungere i componenti di autenticazione

Il codice di esempio è costituito dai componenti seguenti. Aggiungere questi componenti dall'app Android di esempio alla propria app.

Componente Type Origine Descrizione
B2CUser Classe Java Kotlin Rappresenta un utente B2C. Questa classe consente agli utenti di accedere con più criteri.
B2CModeFragment Classe Fragment Java Kotlin Un frammento rappresenta una parte modulare dell'accesso con l'interfaccia utente di Azure AD B2C all'interno dell'attività principale. Questo frammento contiene la maggior parte del codice di autenticazione.
fragment_b2c_mode.xml Layout frammento Java Kotlin Definisce la struttura per un'interfaccia utente per il componente frammento B2CModeFragment.
B2CConfiguration Classe Java Kotlin Un file di configurazione contiene informazioni sul provider di identità di Azure AD B2C. L'app per dispositivi mobili usa queste informazioni per stabilire una relazione di trust con Azure AD B2C, consentire l'accesso e l'uscita degli utenti, acquisire i token e convalidarli. Per altre impostazioni di configurazione, vedere il file auth_config_b2c.json.
auth_config_b2c.json File JSON Java Kotlin Un file di configurazione contiene informazioni sul provider di identità di Azure AD B2C. L'app per dispositivi mobili usa queste informazioni per stabilire una relazione di trust con Azure AD B2C, consentire l'accesso e l'uscita degli utenti, acquisire i token e convalidarli. Per altre impostazioni di configurazione, vedere la classe B2CConfiguration.

Passaggio 3: Configurare l'app Android

Dopo aver aggiunto i componenti di autenticazione, configurare l'app Android con le impostazioni di Azure AD B2C. Le impostazioni del provider di identità di Azure AD B2C vengono configurate nella classe auth_config_b2c.json file e B2CConfiguration.

Per indicazioni, vedere Configurare l'app per dispositivi mobili di esempio.

Passaggio 4: Impostare l'URI di reindirizzamento

Configurare la posizione in cui l'applicazione è in ascolto della risposta del token di Azure AD B2C.

  1. Generare un nuovo hash della firma di sviluppo. Ciò cambierà per ogni ambiente di sviluppo.

    Per Windows:

    keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64
    

    Per iOS:

    keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
    

    Per un ambiente di produzione, usare il comando seguente:

    keytool -exportcert -alias SIGNATURE_ALIAS -keystore PATH_TO_KEYSTORE | openssl sha1 -binary | openssl base64
    

    Per altre informazioni sulla firma delle app, vedi Firmare l'app Android.

  2. Selezionare il AndroidManifest.xml principale>dell'app>src>e quindi aggiungere l'attività seguente BrowserTabActivity al corpo dell'applicazione:

    <!--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>
    
  3. Sostituire Signature_Hash con l'hash generato.

  4. Sostituire Package_Name con il nome del pacchetto Android.

Per aggiornare la registrazione dell'app per dispositivi mobili con l'URI di reindirizzamento dell'app, eseguire le operazioni seguenti:

  1. Accedere al portale di Azure.
  2. Se si ha accesso a più tenant, selezionare l'icona Impostazioni nel menu in alto per passare al tenant di Azure AD B2C dal menu Directory e sottoscrizioni .
  3. Cerca e seleziona Azure AD B2C.
  4. Selezionare Registrazioni app e quindi selezionare l'applicazione registrata nel passaggio 2.3: Registrare l'app per dispositivi mobili.
  5. Seleziona Autenticazione.
  6. In Android selezionare Aggiungi URI.
  7. Immettere il nome del pacchetto e l'hash della firma.
  8. Seleziona Salva.

L'URI di reindirizzamento e l'attività BrowserTabActivity dovrebbero essere simili all'esempio seguente:

L'URL di reindirizzamento per Android di esempio è simile al seguente:

msauth://com.azuresamples.msalandroidkotlinapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D

Il filtro finalità usa lo stesso modello, come illustrato nel frammento XML seguente:

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

Passaggio 5: Personalizzare i blocchi predefiniti del codice

Questa sezione descrive i blocchi predefiniti del codice che abilitano l'autenticazione per l'app Android. La tabella seguente elenca i metodi B2CModeFragment e come personalizzare il codice.

Passaggio 5.1: Creare un'istanza di un'applicazione client pubblica

Le applicazioni client pubbliche non sono attendibili per mantenere i segreti dell'applicazione in modo sicuro e non hanno segreti client. In onCreate o onCreateView creare un'istanza di MSAL usando l'oggetto applicazione client pubblica con più account.

La MultipleAccountPublicClientApplication classe viene usata per creare app basate su MSAL che consentono l'accesso contemporaneamente a più account. La classe consente l'accesso con più flussi utente di Azure AD B2C o criteri personalizzati. Ad esempio, gli utenti accedono con un flusso utente di iscrizione o di accesso e versioni successive eseguono un flusso utente del profilo di modifica.

Il frammento di codice seguente illustra come avviare la libreria MSAL con il auth_config_b2c.json file JSON di configurazione.

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

Passaggio 5.2: Caricare gli account

Quando l'app si trova in primo piano, l'app carica l'account esistente per determinare se gli utenti hanno eseguito l'accesso. Usare questo metodo per aggiornare l'interfaccia utente con lo stato di autenticazione. Ad esempio, è possibile abilitare o disabilitare il pulsante di disconnessione.

Il frammento di codice seguente illustra come caricare gli account.

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

Passaggio 5.3: Avviare una richiesta di autorizzazione interattiva

Una richiesta di autorizzazione interattiva è un flusso in cui agli utenti viene richiesto di iscriversi o eseguire l'accesso. Il initializeUI metodo configura l'evento runUserFlowButton click. Quando gli utenti selezionano il pulsante Esegui flusso utente, l'app li porta ad Azure AD B2C per completare il flusso di accesso.

Il runUserFlowButton.setOnClickListener metodo prepara l'oggetto AcquireTokenParameters con i dati pertinenti relativi alla richiesta di autorizzazione. Il acquireToken metodo richiede quindi agli utenti di completare il flusso di iscrizione o di accesso.

Il frammento di codice seguente illustra come avviare la richiesta di autorizzazione interattiva:

val parameters = AcquireTokenParameters.Builder()
        .startAuthorizationFromActivity(activity)
        .fromAuthority(getAuthorityFromPolicyName(policy_list.getSelectedItem().toString()))
        .withScopes(B2CConfiguration.scopes)
        .withPrompt(Prompt.LOGIN)
        .withCallback(authInteractiveCallback)
        .build()

b2cApp!!.acquireToken(parameters)

Passaggio 5.4: Effettuare un callback interattivo della richiesta di autorizzazione

Dopo che gli utenti completano il flusso di autorizzazione, se correttamente o con esito negativo, il risultato viene restituito al getAuthInteractiveCallback() metodo di callback.

Il metodo di callback passa l'oggetto AuthenticationResult o un messaggio di errore nell'oggetto MsalException . Usare questo metodo per:

  • Aggiornare l'interfaccia utente dell'app per dispositivi mobili con le informazioni al termine dell'accesso.
  • Ricaricare l'oggetto accounts.
  • Chiamare un servizio API Web con un token di accesso.
  • Gestire gli errori di autenticazione.

Il frammento di codice seguente illustra l'uso del callback di autenticazione interattiva.

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.")
        }
    }

Passaggio 6: Chiamare un'API Web

Per chiamare un'API Web di autorizzazione basata su token, l'app deve avere un token di accesso valido. L'app esegue le operazioni seguenti:

  1. Acquisisce un token di accesso con le autorizzazioni necessarie (ambiti) per l'endpoint DELL'API Web.
  2. Passa il token di accesso come token di connessione nell'intestazione di autorizzazione della richiesta HTTP usando questo formato:
Authorization: Bearer <access-token>

Quando gli utenti accedono in modo interattivo, l'app ottiene un token di accesso nel getAuthInteractiveCallback metodo di callback. Per le chiamate API Web consecutive, usare la procedura di acquisizione invisibile all'utente del token come descritto in questa sezione.

Prima di chiamare un'API Web, chiamare il metodo con gli ambiti appropriati per l'endpoint acquireTokenSilentAsync dell'API Web. La libreria MSAL esegue le operazioni seguenti:

  1. Tenta di recuperare un token di accesso con gli ambiti richiesti dalla cache dei token. Se il token è presente, viene restituito il token.
  2. Se il token non è presente nella cache dei token, MSAL tenta di usare il token di aggiornamento per acquisire un nuovo token.
  3. Se il token di aggiornamento non esiste o è scaduto, viene restituita un'eccezione. È consigliabile richiedere all'utente di accedere in modo interattivo.

Il frammento di codice seguente illustra come acquisire un token di accesso:

L'evento acquireTokenSilentButton click del pulsante acquisisce un token di accesso con gli ambiti specificati.

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

Il authSilentCallback metodo di callback restituisce un token di accesso e chiama un'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 */
            }
        }
    }

L'esempio seguente illustra come chiamare un'API Web protetta con un token di connessione:

@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()
}

Aggiungere l'autorizzazione per eseguire operazioni di rete

Per eseguire operazioni di rete nell'applicazione, aggiungere l'autorizzazione seguente al manifesto. Per altre informazioni, vedere Connettersi alla rete.

<uses-permission android:name="android.permission.INTERNET"/>

Passaggi successivi

Scopri come: