共用方式為


使用 Azure AD B2C 在您自己的 Android 應用程式中啟用驗證

本文說明如何將 Azure Active Directory B2C (Azure AD B2C) 驗證新增至您自己的 Android 行動應用程式。

使用本文搭配 使用 Azure AD B2C 在範例 Android 應用程式中設定驗證,並以您自己的 Android 應用程式取代範例 Android 應用程式。 完成本文中的指示之後,您的應用程式會透過 Azure AD B2C 接受登入。

必要條件

檢閱使用 Azure AD B2C 在範例 Android 應用程式中設定驗證中的先決條件和整合指示。

建立Android應用程式專案

如果您還沒有 Android 應用程式,請執行下列動作來設定新的專案:

  1. 在 Android Studio 中,選取 [ 啟動新的 Android Studio 專案]。
  2. 選取 [ 基本活動],然後選取 [ 下一步]。
  3. 為您的應用程式命名。
  4. 儲存套件名稱。 您稍後會在 Azure 入口網站 中輸入。
  5. 將語言從 [Kotlin] 變更為 [Java]
  6. 將 [ 最低 API 層級 ] 設定為 [API 19 或更高版本],然後選取 [ 完成]。
  7. 在項目檢視中,選擇下拉式清單中的 [專案] 以顯示來源和非來源專案檔、開啟 app/build.gradle,然後將 targetSdkVersion 設定28

步驟 1:安裝相依性

在 Android Studio 項目視窗中,移至 app>build.gradle,然後新增下列專案:

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

步驟 2:新增驗證元件

範例程式 代碼 是由下列元件所組成。 從範例 Android 應用程式將這些元件新增至您自己的應用程式。

元件 類型 來源 描述
B2CUser 類別 Kotlin Java 代表 B2C 使用者。 這個類別可讓使用者使用多個原則登入。
B2CModeFragment 片段類別 Kotlin Java 片段代表在主要活動內使用 Azure AD B2C 使用者介面登入的模組化部分。 此片段包含大部分的驗證碼。
fragment_b2c_mode.xml 片段版面配置 Kotlin Java 定義 B2CModeFragment 片段元件之使用者介面的結構。
B2CConfiguration 類別 Kotlin Java 組態檔包含 Azure AD B2C 識別提供者的相關信息。 行動應用程式會使用此資訊建立與 Azure AD B2C 的信任關係、將使用者登入及登出、取得權杖,並驗證這些權杖。 如需更多組態設定,請參閱auth_config_b2c.json檔案。
auth_config_b2c.json JSON 檔案 Kotlin Java 組態檔包含 Azure AD B2C 識別提供者的相關信息。 行動應用程式會使用此資訊建立與 Azure AD B2C 的信任關係、將使用者登入及登出、取得權杖,並驗證這些權杖。 如需更多組態設定,請參閱 B2CConfiguration 類別。

步驟 3:設定 Android 應用程式

新增驗證元件之後,請使用 Azure AD B2C 設定來設定 Android 應用程式。 Azure AD B2C 識別提供者設定是在 auth_config_b2c.json 檔案和 B2CConfiguration 類別中設定。

如需指引,請參閱 設定範例行動應用程式

步驟 4:設定重新導向 URI

設定應用程式接聽 Azure AD B2C 令牌回應的位置。

  1. 產生新的開發簽章哈希。 這會針對每個開發環境變更。

    若為 Windows:

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

    如果是 iOS:

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

    針對生產環境,請使用下列命令:

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

    如需簽署應用程式的詳細資訊,請參閱 簽署Android應用程式

  2. 選取應用程式>src>main>AndroidManifest.xml,然後將下列BrowserTabActivity活動新增至應用程式主體:

    <!--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. 將取代 Signature_Hash 為您產生的哈希。

  4. 將取代 Package_Name 為您的 Android 套件名稱。

若要使用您的應用程式重新導向 URI 更新行動應用程式註冊,請執行下列動作:

  1. 登入 Azure 入口網站
  2. 如果您有多個租用戶的存取權,請使用頂端功能表中的 [設定] 圖示,從 [目錄 + 訂用帳戶] 功能表切換至您的 Azure AD B2C 租用戶。
  3. 搜尋並選取 Azure AD B2C
  4. 選取 [應用程式註冊],然後選取您在步驟 2.3:註冊行動應用程式中註冊的應用程式
  5. 選取驗證
  6. 在 [Android] 底下,選取 [新增 URI]。
  7. 輸入套件名稱和簽章哈希
  8. 選取儲存

您的重新導向 URI 和 BrowserTabActivity 活動看起來應該類似下列範例:

範例 Android 的重新導向 URL 如下所示:

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

意圖篩選條件會使用相同的模式,如下列 XML 代碼段所示:

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

步驟 5:自定義程式碼建置組塊

本節說明啟用Android應用程式驗證的程式代碼建置組塊。 下表列出 B2CModeFragment 方法,以及如何自定義程式代碼。

步驟 5.1:具現化公用用戶端應用程式

公用用戶端應用程式不受信任,無法安全地保留應用程式秘密,而且它們沒有客戶端密碼。 在 onCreateonCreateView 中,使用多帳戶公用用戶端應用程式物件具現化 MSAL。

MultipleAccountPublicClientApplication 類別用來建立 MSAL 型應用程式,允許同時登入多個帳戶。 類別允許使用多個 Azure AD B2C 使用者流程或自定義原則登入。 例如,使用者使用 註冊或登入使用者流程和更新版本登入 ,他們會執行 編輯配置檔 使用者流程。

下列代碼段示範如何使用組態 JSON 檔案起始 MSAL 連結庫 auth_config_b2c.json

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

步驟 5.2:載入帳戶

當應用程式來到前景時,應用程式會載入現有的帳戶,以判斷使用者是否已登入。 使用此方法以驗證狀態更新UI。 例如,您可以啟用或停用註銷按鈕。

下列代碼段示範如何載入帳戶。

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

步驟 5.3:啟動互動式授權要求

互動式授權要求是提示用戶註冊或登入的流程。 方法 initializeUI 會設定 runUserFlowButton click 事件。 當使用者選取 [ 執行使用者流程 ] 按鈕時,應用程式會帶他們前往 Azure AD B2C 來完成登入流程。

方法 runUserFlowButton.setOnClickListenerAcquireTokenParameters 準備物件,其中包含有關授權要求的相關數據。 然後 acquireToken ,方法會提示使用者完成註冊或登入流程。

下列代碼段示範如何啟動互動式授權要求:

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

b2cApp!!.acquireToken(parameters)

步驟 5.4:進行互動式授權要求回呼

使用者完成授權流程之後,無論成功還是失敗,結果會傳回回回 getAuthInteractiveCallback() 呼方法。

回呼方法會傳遞 AuthenticationResult 物件,或物件中的 MsalException 錯誤訊息。 使用此方法:

  • 使用登入完成後的資訊更新行動應用程式UI。
  • 重載 accounts 物件。
  • 使用存取令牌呼叫 Web API 服務。
  • 處理驗證錯誤。

下列代碼段示範如何使用互動式驗證回呼。

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

步驟 6:呼叫 Web API

若要呼叫 令牌型授權 Web API,應用程式必須具有有效的存取令牌。 應用程式會執行下列動作:

  1. 取得具有 Web API 端點所需許可權(範圍)的存取令牌。
  2. 使用下列格式,將存取令牌當做 HTTP 要求的授權標頭中的持有人令牌傳遞:
Authorization: Bearer <access-token>

當使用者 以互動方式登入時,應用程式會在回呼方法中 getAuthInteractiveCallback 取得存取令牌。 針對連續的 Web API 呼叫,請使用取得令牌無訊息程式,如本節所述。

在您呼叫 Web API 之前,請使用 Web API 端點的適當範圍呼叫 acquireTokenSilentAsync 方法。 MSAL 連結庫會執行下列動作:

  1. 嘗試從令牌快取擷取具有要求範圍的存取令牌。 如果令牌存在,則會傳回令牌。
  2. 如果令牌不存在於令牌快取中,MSAL 會嘗試使用其重新整理令牌來取得新的令牌。
  3. 如果重新整理令牌不存在或已過期,則會傳回例外狀況。 建議您提示使用者 以互動方式登入。

下列代碼段示範如何取得存取權杖:

按兩下 acquireTokenSilentButton 按鈕事件會取得具有所提供範圍的存取令牌。

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

authSilentCallback 呼方法會傳回存取令牌,並呼叫 Web API:

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 */
            }
        }
    }

下列範例示範如何使用持有人令牌呼叫受保護的Web API:

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

新增執行網路作業的許可權

若要在應用程式中執行網路作業,請將下列許可權新增至指令清單。 如需詳細資訊,請參閱 連線到網路

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

下一步

了解如何: