Condividi tramite


Esercitazione - Consentire l'accesso degli utenti all'app per dispositivi mobili Android (Kotlin)

Questa è la terza esercitazione della serie di esercitazioni relative all'accesso degli utenti usando Microsoft Entra per ID esterno.

In questa esercitazione si apprenderà come:

  • Consentire l'accesso degli utenti
  • SignOutUser

Prerequisiti

Esercitazione - Preparare l'app Android per l'autenticazione.

Consentire l'accesso degli utenti

Sono disponibili due opzioni principali per consentire l'accesso degli utenti tramite MSAL (Microsoft Authentication Library) per Android: l'acquisizione di token in modo interattivo o invisibile all'utente.

  1. Per l'accesso dell'utente in modo interattivo, usare il codice seguente:

        private fun acquireTokenInteractively() {
        binding.txtLog.text = ""
    
        if (account != null) {
            Toast.makeText(this, "An account is already signed in.", Toast.LENGTH_SHORT).show()
            return
        }
    
        /* Extracts a scope array from text, i.e. from "User.Read User.ReadWrite" to ["user.read", "user.readwrite"] */
        val scopes = scopes.lowercase().split(" ")
        val parameters = AcquireTokenParameters.Builder()
            .startAuthorizationFromActivity(this@MainActivity)
            .withScopes(scopes)
            .withCallback(getAuthInteractiveCallback())
            .build()
    
        authClient.acquireToken(parameters)
    }
    

    Il codice avvia il processo di acquisizione di un token in modo interattivo tramite MSAL per Android. In primo luogo, esso cancella il campo del registro di testo. Successivamente, verifica se è già presente un account connesso; in caso affermativo, viene visualizzato un messaggio di avviso popup che indica che un account è già connesso e restituisce informazioni.

    A questo punto, estrae gli ambiti dall'input di testo e li converte in lettere minuscole prima di suddividerli in una matrice. Utilizzando questi ambiti, compila i parametri per l'acquisizione di un token, incluso l'avvio del processo di autorizzazione dall'attività corrente e la specifica di un callback. Infine, chiama acquireToken() sul client di autenticazione con i parametri costruiti per avviare il processo di acquisizione del token.

    Nel codice in cui si specifica il callback, viene utilizzata una funzione denominata getAuthInteractiveCallback(). La funzione deve avere il codice seguente:

    private fun getAuthInteractiveCallback(): AuthenticationCallback {
        return 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")
                Log.d(TAG, "ID Token: " + authenticationResult.account.claims?.get("id_token"))
                Log.d(TAG, "Claims: " + authenticationResult.account.claims
    
                /* Reload account asynchronously to get the up-to-date list. */
                CoroutineScope(Dispatchers.Main).launch {
                    accessToken = authenticationResult.accessToken
                    getAccount()
    
                    binding.txtLog.text = getString(R.string.log_token_interactive) +  accessToken
                }
            }
    
            override fun onError(exception: MsalException) {
                /* Failed to acquireToken */
                Log.d(TAG, "Authentication failed: $exception")
    
                accessToken = null
                binding.txtLog.text = getString(R.string.exception_authentication) + 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.");
            }
        }
    }
    

    Il frammento di codice definisce una funzione, getAuthInteractiveCallback, che restituisce un'istanza di AuthenticationCallback. All'interno di questa funzione viene creata una classe anonima che implementa l'interfaccia AuthenticationCallback.

    Quando l'autenticazione viene completata (onSuccess), registra l'autenticazione riuscita, recupera il token ID e le attestazioni, aggiorna il token di accesso in modo asincrono usando CoroutineScope, quindi aggiorna l'interfaccia utente con il nuovo token di accesso. Il codice recupera il token ID dall'oggetto authenticationResult e lo registra. Le attestazioni nel token contengono informazioni sull'utente, ad esempio il nome, l'indirizzo e-mail o altre informazioni sul profilo. È possibile recuperare le attestazioni associate all'account corrente accedendo a authenticationResult.account.claims.

    Se si verifica un errore di autenticazione (onError), esso registra l'errore, cancella il token di accesso, aggiorna l'interfaccia utente con il messaggio di errore e fornisce una gestione più specifica per MsalClientException e MsalServiceException. Se l'utente annulla l'autenticazione (onCancel), registra l'annullamento.

    Assicurarsi di includere le istruzioni per l'importazione. Android Studio deve includere automaticamente le istruzioni per l'importazione.

  2. Per consentire l'accesso utente in modo invisibile all'utente, usare il codice seguente:

        private fun acquireTokenSilently() {
        binding.txtLog.text = ""
    
        if (account == null) {
            Toast.makeText(this, "No account available", Toast.LENGTH_SHORT).show()
            return
        }
    
        /* Extracts a scope array from text, i.e. from "User.Read User.ReadWrite" to ["user.read", "user.readwrite"] */
        val scopes = scopes.lowercase().split(" ")
        val parameters = AcquireTokenSilentParameters.Builder()
            .forAccount(account)
            .fromAuthority(account!!.authority)
            .withScopes(scopes)
            .forceRefresh(false)
            .withCallback(getAuthSilentCallback())
            .build()
    
        authClient.acquireTokenSilentAsync(parameters)
    }
    

    Il codice avvia il processo di acquisizione di un token in modo invisibile all'utente. In primo luogo, cancella il registro di testo. Verifica quindi se è disponibile un account; in caso contrario, viene visualizzato un messaggio di avviso popup che indica tale informazione e si chiude. A questo punto, estrae gli ambiti dall'input di testo, li converte in lettere minuscole e li suddivide in una matrice.

    Utilizzando questi ambiti, costruisce i parametri per l'acquisizione di un token in modo invisibile all'utente, specificando l'account, l'autorità, gli ambiti e il callback. Infine, attiva acquireTokenSilentAsync() in modo asincrono sul client di autenticazione con i parametri costruiti, avviando il processo di acquisizione del token in modo invisibile all'utente.

    Nel codice in cui si specifica il callback, viene utilizzata una funzione denominata getAuthSilentCallback(). La funzione deve avere il codice seguente:

    private fun getAuthSilentCallback(): SilentAuthenticationCallback {
        return object : SilentAuthenticationCallback {
            override fun onSuccess(authenticationResult: IAuthenticationResult?) {
                Log.d(TAG, "Successfully authenticated")
    
                /* Display Access Token */
                accessToken = authenticationResult?.accessToken
                binding.txtLog.text = getString(R.string.log_token_silent) + accessToken
            }
    
            override fun onError(exception: MsalException?) {
                /* Failed to acquireToken */
                Log.d(TAG, "Authentication failed: $exception")
    
                accessToken = null
                binding.txtLog.text = getString(R.string.exception_authentication) + exception
    
                when (exception) {
                    is MsalClientException -> {
                        /* Exception inside MSAL, more info inside MsalError.java */
                    }
                    is MsalServiceException -> {
                        /* Exception when communicating with the STS, likely config issue */
                    }
                    is MsalUiRequiredException -> {
                        /* Tokens expired or no session, retry with interactive */
                    }
                }
            }
    
        }
    }
    

    Il codice definisce un callback per l'autenticazione in modo invisibile all'utente. Quindi implementa l'interfaccia SilentAuthenticationCallback, eseguendo l'override di due metodi. Nel metodo onSuccess registra l'autenticazione riuscita e visualizza il token di accesso.

    Nel metodo onError registra l'errore di autenticazione, gestisce diversi tipi di eccezioni, ad esempio MsalClientException e MsalServiceException, quindi suggerisce, se necessario, di riprovare con l'autenticazione interattiva.

    Assicurarsi di includere le istruzioni per l'importazione. Android Studio deve includere automaticamente le istruzioni per l'importazione.

Disconnettersi

Per disconnettere un utente dall'app Android (Kotlin) tramite MSAL per Android, usare il codice seguente:

private fun removeAccount() {
    binding.userName.text = ""
    binding.txtLog.text = ""

    authClient.signOut(signOutCallback())
}

Il codice rimuove un account dall'applicazione. Cancella il nome utente visualizzato e il registro di testo. A questo punto, attiva il processo di disconnessione usando il client di autenticazione, specificando un callback di disconnessione per gestire il completamento dell'operazione di disconnessione.

Nel codice in cui si specifica il callback, viene utilizzata una funzione denominata signOutCallback(). La funzione deve avere il codice seguente:

private fun signOutCallback(): ISingleAccountPublicClientApplication.SignOutCallback {
    return object : ISingleAccountPublicClientApplication.SignOutCallback {
        override fun onSignOut() {
            account = null
            updateUI(account)
        }

        override fun onError(exception: MsalException) {
            binding.txtLog.text = getString(R.string.exception_remove_account) + exception
        }
    }
}

Il codice definisce un callback di disconnessione per un singolo account nell'applicazione client pubblica. Quindi implementa l'interfaccia ISingleAccountPublicClientApplication.SignOutCallback, eseguendo l'override di due metodi.

Nel metodo onSignOut annulla l'account corrente e aggiorna di conseguenza l'interfaccia utente. Nel metodo onError registra eventuali errori che si verifichino durante il processo di disconnessione e aggiorna il registro di testo con il messaggio di eccezione corrispondente.

Assicurarsi di includere le istruzioni per l'importazione. Android Studio deve includere automaticamente le istruzioni per l'importazione.

Passaggi successivi

Esercitazione - Chiamare un'API Web protetta in un'app Android (Kotlin).