Partager via


Tutoriel : ajouter une fonctionnalité de connexion dans une application Android en utilisant l’authentification native

Ce tutoriel montre comment connecter et déconnecter un utilisateur dans votre application mobile Android avec un code secret à usage unique envoyé par e-mail ou un nom d’utilisateur et un mot de passe en utilisant l’authentification native.

Dans ce tutoriel, vous allez apprendre à :

  • Connecter un utilisateur avec un code secret à usage unique envoyé par e-mail ou un nom d’utilisateur (e-mail) et un mot de passe.
  • Déconnecter un utilisateur.
  • Gérer l’erreur de connexion

Prérequis

Connecter un utilisateur

Pour connecter un utilisateur en utilisant le code secret à usage unique, collectez son e-mail, puis envoyez-lui un e-mail contenant un code secret à usage unique pour lui permettre de confirmer son e-mail. Lorsque l’utilisateur entre un code secret à usage unique valide, l’application le connecte.

Pour connecter un utilisateur en utilisant le nom d’utilisateur (e-mail) et le mot de passe, collectez l’e-mail et le mot de passe de l’utilisateur. Si le nom d’utilisateur et le mot de passe sont valides, l’application connecte l’utilisateur.

Pour connecter un utilisateur, vous devez :

  1. Créer une interface utilisateur pour :

    • Collecter une adresse e-mail de l’utilisateur. Ajouter une validation à vos entrées pour vérifier que l’utilisateur entre une adresse e-mail valide.
    • Collecter un mot de passe si vous vous inscrivez avec un nom d’utilisateur (e-mail) et un mot de passe.
    • Collectez un code secret à usage unique par e-mail auprès de l’utilisateur si vous vous connectez avec un code secret à usage unique.
    • Renvoyez un code secret à usage unique (recommandé) si vous vous connectez avec un code secret à usage unique par e-mail.
  2. Dans votre IU, ajoutez un bouton dont l’événement de sélection démarre une connexion, comme indiqué dans l’extrait de code suivant :

     CoroutineScope(Dispatchers.Main).launch {
         val actionResult = authClient.signIn(
             username = emailAddress
             //password = password, Pass 'password' param if you sign in with username (email) and password
         )
         if (actionResult is SignInResult.CodeRequired) {
             val nextState = actionResult.nextState
             val submitCodeActionResult = nextState.submitCode(
                 code = code
             )
             if (submitCodeActionResult is SignInResult.Complete){
                 // Handle sign in success
                 val accountState = submitCodeActionResult.resultValue
                 val accessTokenResult = accountState.getAccessToken()
                 if (accessTokenResult is GetAccessTokenResult.Complete) {
                     val accessToken = accessTokenResult.resultValue.accessToken
                     val idToken = accountState.getIdToken()
                 }
             }
         }
     }
    

    Si l’utilisateur n’est pas obligé de soumettre un code secret, par exemple lorsqu’il se connecte avec une adresse e-mail et un mot de passe, utilisez l’extrait de code suivant :

        CoroutineScope(Dispatchers.Main).launch {
            val actionResult = authClient.signIn(
                username = emailAddress,
                password = password
            )
            if (actionResult is SignInResult.Complete) -> {
                // Handle sign in success
                val accountState = actionResult.resultValue
                val accessTokenResult = accountState.getAccessToken()
                if (accessTokenResult is GetAccessTokenResult.Complete) {
                        val accessToken = accessTokenResult.resultValue.accessToken
                        val idToken = accountState.getIdToken()
                    }
            }
        }
    
    • Pour démarrer le flux de connexion, utilisez la méthode signIn(username) ou signIn(username, password) du Kit de développement logiciel (SDK).
    • Le paramètre de la méthode, username, correspond à l’adresse e-mail que vous collectez auprès de l’utilisateur.
    • Si la méthode de connexion nécessite un nom d’utilisateur (e-mail) et un mot de passe, le paramètre de la méthode, password, est alors le mot de passe que vous collectez auprès de l’utilisateur.
    • Dans le scénario le plus courant, signIn(username) ou signIn(username, password) retourne un résultat, SignInResult.CodeRequired, qui indique que le SDK s’attend à ce que l’application soumette le code secret à usage unique envoyé par e-mail à l’adresse e-mail de l’utilisateur.
    • L’objet SignInResult.CodeRequired contient une référence au nouvel état, que nous pouvons récupérer via actionResult.nextState.
    • Le nouvel état nous donne accès à deux nouvelles méthodes :
      • submitCode() soumet le code secret à usage unique envoyé par e-mail que l’application collecte auprès de l’utilisateur.
      • resendCode() renvoie le code secret à usage unique envoyé par e-mail si l’utilisateur ne reçoit pas le code.

Gérer les erreurs de connexion

Pendant la connexion, toutes les actions n’aboutissent pas. Par exemple, c’est le cas si l’utilisateur tente de se connecter avec une adresse e-mail qui n’existe pas ou s’il envoie un code non valide.

Gérer les erreurs au début du processus de connexion

Pour gérer les erreurs dans la méthode signIn(username) ou signIn(username, password), utilisez l’extrait de code suivant :

val actionResult = authClient.sign(
    username = emailAddress
    //password = password, Pass 'password' param if you sign in with username (email) and password
)
if (actionResult is SignInResult.CodeRequired) {
    // Next step: submit code
} else if (actionResult is SignInError) {
    // Handle sign in errors
    when {
         actionResult.isUserNotFound() -> {
             // Handle "user not found" error
         }
         actionResult.isAuthNotSupported() -> {
         // Handle "authentication type not support" error
         }
         actionResult.isInvalidCredentials() -> {
             // Handle specific errors
         }
         else -> {
             // Handle other errors
         }
     }
}
  • SignInError indique un résultat d’action infructueux, retourné par signIn(). Le résultat de l’action n’inclut donc pas de référence au nouvel état.
  • Si actionResult is SignUpError, le kit Android SDK fournit des méthodes utilitaires qui vous permettent d’analyser les erreurs spécifiques de manière plus détaillée :
    • La méthode isUserNotFound() vérifie si l’utilisateur se connecte avec un nom d’utilisateur (adresse e-mail) qui n’existe pas.
    • La méthode isBrowserRequired() vérifie si un navigateur (secours web) est nécessaire pour effectuer le flux d’authentification. Ce scénario se produit quand l’authentification native n’est pas suffisante pour effectuer le flux d’authentification. Par exemple, un administrateur configure l’adresse e-mail et le mot de passe en tant que méthode d’authentification, mais l’application ne parvient pas à envoyer password en tant que type de demande, ou ne le prend tout simplement pas en charge. Suivez les étapes décrites dans Prise en charge du secours web dans l’application Android pour gérer ce scénario quand il se produit.
    • La méthode isAuthNotSupported() vérifie si l’application envoie un type de demande que Microsoft Entra ne prend pas en charge, c’est-à-dire une valeur de type de demande autre que oob et password. Découvrez plus en détail les types de demandes.
    • Pour une connexion par nom d’utilisateur (e-mail) et mot de passe, la méthode isInvalidCredentials() vérifie si la combinaison nom d’utilisateur et mot de passe est incorrecte.

Gérer les erreurs liées au code soumis

Pour gérer les erreurs de la méthode submitCode(), utilisez l’extrait de code suivant :

val submitCodeActionResult = nextState.submitCode(
    code = code
)
if (submitCodeActionResult is SignInResult.Complete) {
    // Sign in flow complete, handle success state.
} else if (submitCodeActionResult is SubmitCodeError && submitCodeActionResult.isInvalidCode()) {
    // Handle "invalid code" error
}
  • L’erreur SubmitCodeError indique un résultat d’action infructueux, retourné par submitCode(). Le résultat de l’action n’inclut donc pas de référence au nouvel état.
  • isInvalidCode() vérifie l’erreur spécifique. Dans ce cas, la référence à l’état précédent doit être utilisée pour effectuer de nouveau l’action.

Pour récupérer le nouveau code secret à usage unique envoyé par e-mail, utilisez l’extrait de code suivant :

val submitCodeActionResult = nextState.submitCode(
    code = code
)
if (submitCodeActionResult is SignInError && submitCodeActionResult.isInvalidCode) {
    // Inform the user that the submitted code was incorrect or invalid, then ask them to input a new email one-time passcode
    val newCode = retrieveNewCode()
    nextState.submitCode(
        code = newCode
    )
}

Vous avez mené à bien toutes les étapes nécessaires pour connecter correctement un utilisateur sur votre application. Créez et exécutez votre application. En principe, vous devez pouvoir fournir une adresse e-mail, recevoir un code à cette adresse et utiliser ce code pour connecter l’utilisateur.

Lire les revendications de jeton d’ID

Une fois que votre application a acquis un jeton d’ID, vous pouvez récupérer les revendications associées au compte actif. Pour ce faire, utilisez l’extrait de code suivant.

val preferredUsername = accountState.getClaims()?.get("preferred_username")
val city = accountState.getClaims()?.get("City")
val givenName = accountState.getClaims()?.get("given_name")
//custom attribute
val loyaltyNumber = accountState.getClaims()?.get("loyaltyNumber")

La clé que vous utilisez pour accéder à la valeur de revendication est le nom que vous spécifiez quand vous ajoutez l’attribut utilisateur en tant que revendication de jeton.

Pour savoir comment ajouter des attributs intégrés et personnalisés aux revendications de jeton, consultez l’article Ajouter des attributs utilisateur aux revendications de jeton.

Déconnecter un utilisateur

Pour déconnecter un utilisateur, vous devez supprimer le compte stocké dans le cache.

  1. Créez votre interface utilisateur (IU) personnalisé comprenant :

    • Un bouton de déconnexion que l’utilisateur sélectionne pour envoyer une demande de déconnexion.
  2. Pour déconnecter un utilisateur, utilisez le code suivant :

    private fun performSignOut(accountState: AccountState) {
         CoroutineScope(Dispatchers.Main).launch {
            val accountResult = authClient.getCurrentAccount()
             if (accountResult is GetAccountResult.AccountFound) {
                 val signOutResult = accountResult.resultValue.signOut()
                 if (signOutResult is SignOutResult.Complete) {
                     // Show sign out successful UI
                 }
             }
         }
     }
    

Gérer les erreurs de déconnexion

La déconnexion doit se dérouler sans erreur. Si des erreurs se produisent, inspectez le résultat de l’erreur à l’aide de l’extrait de code suivant :

val actionResult = accountResult.signOut()
if (actionResult is SignOutResult.Complete) {
    // Show sign out successful UI
} else {
    // Handle errors
}

Veillez à inclure les instructions import. Android Studio doit inclure automatiquement les instructions import.

Vous avez mené à bien toutes les étapes nécessaires pour déconnecter correctement un utilisateur sur votre application. Créez et exécutez votre application. Normalement, vous devriez pouvoir sélectionner le bouton de déconnexion et faire aboutir la déconnexion.

Configurer un fournisseur de revendications personnalisé

Si vous souhaitez ajouter des revendications à partir d’un système externe au jeton émis pour votre application, utilisez un fournisseur de revendications personnalisé. Un fournisseur de revendications personnalisé est constitué d’une extension d’authentification personnalisée qui appelle une API REST externe pour récupérer des revendications provenant de systèmes externes.

Suivez les étapes détaillées dans Configurer un fournisseur de revendications personnalisé pour ajouter des revendications à partir d’un système externe dans vos jetons de sécurité.