教程:在 Android (Kotlin) 移动应用中登录用户
这是本教程系列中的第三个教程,介绍如何使用 Microsoft Entra 外部 ID 登录用户。
在本教程中,你将:
- 登录用户
- 注销用户
先决条件
登录用户
可通过两个主要选项使用适用于 Android 的 Microsoft 身份验证库 (MSAL) 登录用户:以交互方式或无提示方式获取令牌。
若要以交互方式登录用户,请使用以下代码:
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) }
该代码会启动使用适用于 Android 的 MSAL 以交互方式获取令牌的过程。 它首先会清除文本日志字段。 然后,它会检查是否有已登录帐户,如果有,会显示一条 Toast 消息,指示帐户已登录,然后返回。
接下来,它会从文本输入中提取范围并将其转换为小写,然后再将它们拆分为数组。 使用这些范围,它会生成用于获取令牌的参数,包括从当前活动启动授权过程并指定回叫。 最后,它使用构造的参数在身份验证客户端上调用
acquireToken()
,以启动令牌获取过程。在代码中指定回叫的位置,使用一个名为
getAuthInteractiveCallback()
的函数。 该函数应具有以下代码: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."); } } }
该代码片段定义了函数
getAuthInteractiveCallback
,该函数会返回AuthenticationCallback
的实例。 在此函数中,将创建一个实现AuthenticationCallback
接口的匿名类。身份验证成功 (
onSuccess
) 后,它将记录成功的身份验证、检索 ID 令牌和声明、使用CoroutineScope
异步更新访问令牌,并使用新的访问令牌更新 UI。 该代码会从authenticationResult
检索 ID 令牌并进行记录。 令牌中的声明包含有关用户的信息,例如其名称、电子邮件或其他配置文件信息。 可以通过访问authenticationResult.account.claims
检索与当前帐户关联的声明。如果存在身份验证错误 (
onError
),则会记录错误、清除访问令牌、使用错误消息更新 UI,并为MsalClientException
和MsalServiceException
提供更具体的处理。 如果用户取消身份验证 (onCancel
),则会记录取消。确保包含 import 语句。 Android Studio 应该会自动为你包含 import 语句。
若要以无提示方式登录用户,请使用以下代码:
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) }
该代码会启动以无提示方式获取令牌的过程。 它首先会清除文本日志。 然后,它会检查是否有可用帐户;如果没有,将显示一条 toast 消息,指示没有可用账户,然后退出。 接下来,它会从文本输入中提取范围,将其转换为小写,然后再将它们拆分为数组。
使用这些范围,它会构造以无提示方式获取令牌的参数,指定帐户、颁发机构、范围和回叫。 最后,它会使用构造的参数在身份验证客户端上异步触发
acquireTokenSilentAsync()
,启动无提示的令牌获取过程。在代码中指定回叫的位置,使用一个名为
getAuthSilentCallback()
的函数。 该函数应具有以下代码: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 */ } } } } }
该代码定义了用于无提示身份验证的回叫。 它可实现
SilentAuthenticationCallback
接口,重写两种方法。 在onSuccess
方法中,它会记录成功的身份验证并显示访问令牌。在
onError
方法中,它会记录身份验证失败,处理不同类型的异常,例如MsalClientException
和MsalServiceException
,并根据需要建议使用交互式身份验证重试。确保包含 import 语句。 Android Studio 应该会自动为你包含 import 语句。
注销
若要使用适用于 Android 的 MSAL 从 Android 应用注销用户,请使用以下代码:
private fun removeAccount() {
binding.userName.text = ""
binding.txtLog.text = ""
authClient.signOut(signOutCallback())
}
该代码会从应用程序中移除帐户。 它会清除显示的用户名和文本日志。 然后,它会使用身份验证客户端触发注销过程,并指定注销回叫来处理注销操作的完成。
在代码中指定回叫的位置,使用一个名为 signOutCallback()
的函数。 该函数应具有以下代码:
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
}
}
}
该代码为公共客户端应用程序中的单个帐户定义注销回叫。 它可实现 ISingleAccountPublicClientApplication.SignOutCallback
接口,重写两种方法。
在 onSignOut
方法中,它会使当前帐户无效,并相应地更新用户界面。 在 onError
方法中,它会记录注销过程中发生的任何错误,并使用相应的异常消息更新文本日志。
确保包含 import 语句。 Android Studio 应该会自动为你包含 import 语句。