教程:使用本机身份验证在 Android 移动应用中添加注册

适用于绿色圆圈,带有白色复选标记符号,指示以下内容适用于外部租户。 外部租户(了解详细信息

本教程演示如何使用本机身份验证在 Android 移动应用中使用电子邮件一次性密码或用户名(电子邮件)和密码注册用户。 你还将了解如何在注册期间收集用户属性,包括用户名(别名),并处理错误。

在本教程中,你将:

  • 使用电子邮件一次性密码或用户名(电子邮件)和密码注册用户。
  • 在注册期间收集用户属性,包括用户名(别名)。
  • 处理注册错误。

先决条件

注册用户

若要使用电子邮件一次性密码或用户名(电子邮件)和密码注册用户,请从用户收集电子邮件,然后向用户发送电子邮件,其中包含一次性密码的电子邮件。 用户输入有效的电子邮件一次性密码以验证其用户名。

若要注册用户,需要:

  1. 创建用户界面 (UI) 以:

    • 从用户处收集电子邮件。 向输入中添加验证,以确保用户输入有效的电子邮件地址。
    • 如果使用用户名(电子邮件)和密码注册,请收集密码。
    • 如果应用支持基于别名的登录,请收集用户名(别名)。
    • 从用户处收集电子邮件一次性密码。
    • 如果需要,收集用户属性。
    • 重新发送一次性密码(推荐)。
    • 开始注册流程。
  2. 在应用中添加一个按钮,其选择事件会触发以下代码片段:

    CoroutineScope(Dispatchers.Main).launch {
         val parameters = NativeAuthSignUpParameters(username = email)
         // Assign 'password' param if you sign in with username (email) and password
         // parameters.password = password
         val actionResult: SignUpResult = authClient.signUp(parameters)
    
         if (actionResult is SignUpResult.CodeRequired) {
             val nextState = actionResult.nextState
             val submitCodeActionResult = nextState.submitCode(
                code = code
             )
             if (submitCodeActionResult is SignUpResult.Complete) {
                // Handle sign up success
             }
        }
    }
    
    • 使用 SDK 的 signUp(parameters) 实例方法启动注册流。
    • 若要使用用户名(电子邮件地址)和密码注册,请创建 NativeAuthSignUpParameters 类的实例,并分配用户名和密码。
    • 注册参数 username是从用户那里收集的电子邮件地址。
    • 在大多数常见情况下,signUp(parameters) 会返回一个结果 SignUpResult.CodeRequired,这表明 SDK 期望应用提交发送到用户电子邮件地址的一次性电子邮件验证码。
    • 对象 SignUpResult.CodeRequired 包含一个新的状态引用,可以通过 actionResult.nextState 检索。
    • 通过新状态可以访问两个新方法:
      • submitCode() 会提交应用从用户那里收集的电子邮件一次性密码。
      • 如果用户没有收到电子邮件一次性密码,resendCode() 会重新发送它。
    • submitCode() 会返回 SignUpResult.Complete,这指示流已完成且用户已注册。
    • signUp(parameters) 还可以返回 SignUpError 来表示发生了错误。

在注册期间收集用户属性

无论是使用电子邮件一次性密码还是用户名(电子邮件)和密码注册用户,都可以在创建用户帐户之前收集用户属性:

  • NativeAuthSignUpParameters 实例接受 attributes 参数:

        CoroutineScope(Dispatchers.Main).launch {
            val parameters = NativeAuthSignUpParameters(username = email)
            // Assign 'password' param if you sign in with username (email) and password
            // parameters.password = password
            parameters.attributes = userAttributes
            val actionResult: SignUpResult = authClient.signUp(parameters)
            //...
        }
    
  • Android SDK 提供实用工具类 UserAttribute.Builder,用于创建用户属性。 例如,若要提交 citycountry 用户属性,请使用以下代码片段生成 userAttributes 变量:

         val userAttributes = UserAttributes.Builder ()
        .country(country) 
        .city(city) 
        .build()   
    

    UserAttribute.Builder 类中的方法名称与其构建的用户属性的可编程名称相同。 详细了解 Android SDK 属性生成器

  • signUp(parameters) 方法可以返回 SignUpResult.AttributesRequired,以指示应用需要在Microsoft Entra 创建帐户之前提交一个或多个必需属性。 管理员将这些属性配置为 Microsoft Entra 管理中心中的必需属性。 Microsoft Entra 不会明确请求可选用户属性。

  • SignUpResult.AttributesRequired 结果包含 requiredAttributes 参数。 requiredAttributesRequiredUserAttribute 对象的列表,其中包含有关用户属性的详细信息,应用需要提交这些属性。 若要处理 actionResult is SignUpResult.AttributesRequired,请使用以下代码片段:

    val parameters = NativeAuthSignUpParameters(username = email)
    // Assign 'password' param if you sign in with username (email) and password
    // parameters.password = password
    parameters.attributes = userAttributes
    val actionResult: SignUpResult = authClient.signUp(parameters)
    
    if (actionResult is SignUpResult.AttributesRequired) {
            val requiredAttributes = actionResult.requiredAttributes 
            // Handle "attributes required" result 
            val nextState = actionResult.nextState
            nextState.submitAttributes(
                attributes = moreAttributes
            )
    }
    

注册期间收集用户名(别名)

用户名(别名)是一个特殊的用户属性。 与城市或国家/地区等其他信息一样,你会在注册时收集这些信息。 与这些属性不同,用户稍后可以使用别名登录。 别名(例如,“johndoe”)为用户提供比电子邮件地址更短、更友好的登录方式。

用户名(别名)不会替换用户名(电子邮件)。 在注册期间,应用必须始终将用户名(电子邮件)收集为主标识符,并将别名作为属性与电子邮件一起收集。 登录时,用户可以选择使用用户名(电子邮件)或用户名(别名)登录。

当在注册用户流程中启用 Username 内置用户属性时,SDK 会通过用于其他属性的同一个 UserAttributes 构建器,使用 flatUsername() 方法来接收该属性。 可以直接在注册调用中传递用户名(别名),以便用户无需通过单独的属性所需的步骤。

若要收集用户名(别名),请将注册 UI 中用户名的输入字段与电子邮件字段一起添加,然后在注册调用中将别名作为属性传递:

val email = binding.emailText.text.toString()
val password = binding.passwordText.text.toString()
val username = binding.usernameText.text.toString()

val attributes = UserAttributes.Builder()
    .flatUsername(username)
    .build()

CoroutineScope(Dispatchers.Main).launch {
    val actionResult = authClient.signUpUsingPassword(
        username = email,
        password = password,
        attributes = attributes
    )

    when (actionResult) {
        is SignUpResult.CodeRequired -> {
            // Navigate to code verification
            navigateToCodeVerification(actionResult.nextState)
        }
        is SignUpUsingPasswordError -> {
            handleSignUpError(actionResult)
        }
    }
}

对于电子邮箱一次性验证码流程(无需密码),请使用 signUp,而不要使用 signUpUsingPassword

val actionResult = authClient.signUp(
    username = email,
    attributes = attributes
)

处理注册错误

在注册期间,并非所有操作都能成功。 例如,用户可能会尝试使用已使用的电子邮件地址进行注册或提交无效的电子邮件一次性密码。

处理启动注册错误

若要处理 signUp() 方法的错误,请使用以下代码片段:

 val parameters = NativeAuthSignUpParameters(username = email)
 // Assign 'password' param if you sign in with username (email) and password
 // parameters.password = password
val actionResult: SignUpResult = authClient.signUp(parameters)

if (actionResult is SignUpResult.CodeRequired) {
    // Next step: submit code
} else if (actionResult is SignUpError) {
     when {
         actionResult.isUserAlreadyExists() -> {
             // Handle "user already exists" error
         }
         else -> {
             // Handle other errors
         }
     }
}
  • signUp(parameters) 可以返回 SignUpError

  • SignUpError 表示 signUp() 返回的操作结果不成功,因此不包含对新状态的引用。

  • 如果actionResult is SignUpError,则 Microsoft 身份验证库 (MSAL) Android SDK 提供实用工具方法以进一步分析特定错误:

    • 该方法 isUserAlreadyExists() 检查用户名或别名是否已用于创建帐户。
    • isInvalidAttributes() 会检查应用提交的一个或多个属性是否未通过验证,例如出现错误的数据类型。 它包含一个 invalidAttributes 参数,该参数是应用提交但验证失败的所有属性的列表。
    • isInvalidPassword() 检查密码是否无效,例如当密码不符合所有密码复杂性要求时。 详细了解 Microsoft Entra 的密码策略
    • isInvalidUsername() 检查用户名是否无效,例如用户电子邮件无效时。
    • isBrowserRequired() 检查是否需要浏览器(Web 回退)来完成身份验证流。 当本机身份验证不足以完成身份验证流时,会出现这种情况。 例如,管理员将电子邮件和密码配置为身份验证方法,但应用无法将 密码 作为质询类型发送,或者不支持它。 使用 Android 应用中支持 Web 回退的步骤来处理此场景。
    • isAuthNotSupported() 会检查应用是否在发送 Microsoft Entra 不支持的质询类型,即除 oob 或 password 以外的质询类型值。 详细了解挑战类型

    通过应用 UI 中的友好消息通知用户电子邮件已在使用中,或者某些属性无效。

  • 若要处理属性无效错误,请使用以下代码片段:

    val parameters = NativeAuthSignUpParameters(username = email)
    // Assign 'password' param if you sign in with username (email) and password
    // parameters.password = password
    parameters.attributes = userAttributes
    val actionResult: SignUpResult = authClient.signUp(parameters)
    
    if (actionResult is SignUpError && actionResult.isInvalidAttributes()) {
        val invalidAttributes = actionResult.invalidAttributes
    
        // Handle "invalid attributes" error, this time submit valid attributes
        val parameters = NativeAuthSignUpParameters(username = email)
        // Assign 'password' param if you sign in with username (email) and password
        // parameters.password = password
        parameters.attributes = userAttributes
        authClient.signUp(parameters)
    } 
    //...
    

处理提交电子邮件一次性密码错误

若要处理 submitCode() 方法的错误,请使用以下代码片段:

val submitCodeActionResult = nextState.submitCode(
    code = code
)
if (submitCodeActionResult is SignUpResult.Complete) {
    // Sign up flow complete, handle success state.
} else if (submitCodeActionResult is SubmitCodeError) {
    // Handle errors under SubmitCodeError
     when {
         submitCodeActionResult.isInvalidCode() -> {
             // Handle "code invalid" error
         }
         else -> {
             // Handle other errors
         }
     }
}
  • submitCode() 可以返回 SubmitCodeError

  • 使用 isInvalidCode() 方法检查特定错误,例如“提交的代码无效”。 在这种情况下,必须使用以前的状态引用来重新执行操作。

  • 若要检索新的电子邮件一次性密码,请使用以下代码片段:

    val submitCodeActionResult = nextState.submitCode(
        code = code
    )
    if (submitCodeActionResult is SubmitCodeError && submitCodeActionResult.isInvalidCode()) {
        // Inform the user that the submitted code was incorrect or invalid and ask for a new code to be supplied
        val newCode = retrieveNewCode()
        nextState.submitCode(
            code = newCode
        )
    }
    

确保包含 import 语句。 Android Studio 应该会自动为你添加 import 语句。

你已完成在应用中注册用户所需的所有步骤。 生成并运行应用程序。 如果一切配置正确,则应能够使用电子邮件一次性密码或电子邮件和密码注册用户,并收集用户属性,包括用户名(别名)。

可选:注册流程完成后登录

成功注册流后,无需启动登录流即可登录用户。 如果用户使用用户名(别名)注册,他们可以使用其电子邮件地址或别名登录。 请在教程:在 Android 中注册后登录用户一文中了解详细信息。

后续步骤

教程:在 Android 应用中添加使用电子邮件一次性密码进行登录和退出登录的功能