使用穿戴式裝置進行驗證:Credential Manager

Wear OS 應用程式可在沒有隨附應用程式的情況下獨立執行,這表示 Wear OS 應用程式在存取來自網際網路的資料時,需要自行管理驗證程序。但是手錶的小螢幕尺寸和不完整的輸入功能,使得 Wear OS 應用程式只能使用有限的驗證選項。

本指南說明如何使用建議的 Wear OS 應用程式驗證方法「憑證管理工具」。

如要進一步瞭解如何設計良好的登入體驗,請參閱登入使用者體驗指南

初步考量

開始實作前,請先考量下列事項。

訪客模式

請勿採用一律要求驗證的做法,而是要在使用者不須登入的情況下盡可能提供最多功能。

使用者可能會發現並安裝您的 Wear 應用程式,但未使用相關行動應用程式,因此可能沒有帳戶,也不知道其中提供哪些功能。請確保訪客模式功能可正確展示應用程式的各項功能。

部分裝置可能會延長解鎖時間

在搭載 Wear OS 5 以上版本的支援裝置上,系統會偵測使用者是否將裝置戴在手腕上。如果使用者關閉腕帶偵測功能,然後取下手錶,系統會將裝置解鎖的時間延長。

如果應用程式需要更高層級的安全性 (例如顯示可能含有私密或私密資料時),請先檢查是否已啟用手腕偵測功能:

val wristDetectionEnabled =
        isWristDetectionAutoLockingEnabled(applicationContext)

如果這個方法傳回 false,請提示使用者登入應用程式帳戶,再顯示使用者專屬內容。

Credential Manager

如要在 Wear OS 驗證,建議使用 Credential Manager API。使用者不必連線配對手機,也不必記住密碼,就能在獨立設定中登入 Wear OS 應用程式,享有更安全的環境。

本文將說明開發人員如何透過標準驗證機制實作 Credential Manager 解決方案,包括:

  • 密碼金鑰
  • 密碼
  • 聯合身分識別 (例如「使用 Google 帳戶登入」)

本指南也提供相關指引,說明如何遷移其他可接受的 Wear OS 驗證方法 (資料層權杖共用OAuth),做為 Credential Manager 的備份方法,以及如何處理從已淘汰的獨立 Google 登入按鈕,轉換為內嵌 Credential Manager 版本的特殊指引。

Wear OS 密碼金鑰

我們強烈建議開發人員在 Wear OS 認證管理工具實作中導入密碼金鑰。密碼金鑰是使用者驗證的全新業界標準,可為使用者帶來多項重大好處

密碼金鑰更簡單

  • 使用者可以選取要登入的帳戶。 他們不必輸入使用者名稱。
  • 使用者可以透過裝置的螢幕鎖定進行驗證。
  • 建立及註冊密碼金鑰後,使用者即可順暢切換至新裝置,並立即使用,無須重新註冊。

密碼金鑰更安全

  • 開發人員只會將公開金鑰儲存到伺服器,而不是儲存密碼,這表示惡意行為者入侵伺服器後能取得的價值遠遠降低,而且發生違規事件時,需要清理的資料也大幅減少。
  • 密碼金鑰可防範網路釣魚。密碼金鑰只能用於使用者註冊的網站和應用程式;由於驗證作業是由瀏覽器或作業系統處理,因此使用者不會在欺騙性網站上驗證身分。
  • 密碼金鑰可減少傳送簡訊的需求,讓驗證程序更具成本效益。

實作密碼金鑰

包括所有導入類型的設定和指南。

設定

  1. 在應用程式模組的 build.gradle 檔案中,將目標 API 級別設為 35:

    android {
        defaultConfig {
            targetSdkVersion(35)
        }
    }
    
  2. 在應用程式或模組的 build.gradle 檔案中加入下列程式碼行,並使用androidx.credentials版本參考資料中的最新穩定版。

    androidx.credentials:credentials:1.5.0
    androidx.credentials:credentials-play-services-auth:1.5.0
    

內建驗證方法

由於憑證管理工具是統一的 API,因此 Wear OS 的實作步驟與其他裝置類型相同。

請參閱行動裝置操作說明,瞭解如何開始導入密碼金鑰和密碼支援功能。

在 Credential Manager 中新增「使用 Google 帳戶登入」支援的步驟是針對行動裝置開發作業,但 Wear OS 上的步驟相同。如要瞭解這類情況的特殊考量事項,請參閱「停用舊版『透過 Google 登入』功能」一節。

請注意,由於無法在 Wear OS 上建立憑證,因此您不需要實作行動裝置操作說明中提及的憑證建立方法。

備用驗證方法

Wear OS 應用程式還有兩種可接受的驗證方式:OAuth 2.0 (任一變體) 和 Mobile Auth Token Data Layer Sharing。雖然這些方法在 Credential Manager API 中沒有整合點,但可以納入 Credential Manager 的 UX 流程,做為使用者關閉 Credential Manager 畫面時的回退機制。

如要處理使用者關閉 Credential Manager 畫面的動作,請在 GetCredential 邏輯中擷取 NoCredentialException,然後前往自訂驗證 UI。

yourCoroutineScope.launch {
    try {
      val response = credentialManager.getCredential(activity, request)
      signInWithCredential(response.credential)
    } catch (e: GetCredentialCancellationException) {
      navigateToFallbackAuthMethods()
    }
}

接著,自訂驗證 UI 即可提供登入 UX 指南所述的其他任何可接受的驗證方法。

共用資料層權杖

透過 Wearable Data Layer API,手機隨附應用程式可以安全將驗證資料傳送到 Wear OS 應用程式。以訊息或資料項目形式傳送憑證。

這類驗證通常不需使用者採取任何動作。不過請您避免在不通知使用者要登入的情況下進行驗證。您可以使用可關閉的畫面告知使用者,行動裝置正在轉移他們的帳戶。

重要事項:這種驗證方式僅限和 Android 配對的手錶使用,且須安裝對應的手機應用程式,因此您的 Wear OS 應用程式必須另外提供至少一種驗證方式。請為沒有對應手機應用程式的使用者,或是與 iOS 裝置配對的 Wear OS 裝置使用者,提供替代驗證方式。

透過手機應用程式使用資料層傳遞權杖,如以下範例所示:

val token = "..." // Auth token to transmit to the Wear OS device.
val dataClient: DataClient = Wearable.getDataClient(context)
val putDataReq: PutDataRequest = PutDataMapRequest.create("/auth").run {
    dataMap.putString("token", token)
    asPutDataRequest()
}
val putDataTask: Task<DataItem> = dataClient.putDataItem(putDataReq)

監聽 Wear OS 應用程式的資料變更事件,如以下範例所示:

val dataClient: DataClient = Wearable.getDataClient(context)
dataClient.addListener{ dataEvents ->
    dataEvents.forEach { event ->
        if (event.type == DataEvent.TYPE_CHANGED) {
            val dataItemPath = event.dataItem.uri.path ?: ""
            if (dataItemPath.startsWith("/auth")) {
                val token = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("token")
                // Display an interstitial screen to notify the user that
                // they're being signed in.
                // Then, store the token and use it in network requests.
            }
        }
    }
}

如要進一步瞭解如何使用 Wearable Data Layer,請參閱「在 Wear OS 上傳送資料和進行同步處理」。

使用 OAuth 2.0

Wear OS 支援兩種 OAuth 2.0 流程,如後續章節所述:

  • 搭配 Proof Key for Code Exchange (PKCE) 使用 Authorization Code Grant (授權碼許可),如 RFC 7636 中定義
  • 裝置授權許可 (DAG),如 RFC 8628 中定義
Proof Key for Code Exchange (PKCE)

如要有效利用 PKCE,請使用 RemoteAuthClient。接著,如要透過 Wear OS 應用程式對 OAuth 提供者執行驗證要求,請建立 OAuthRequest 物件。這個物件包含用於取得權杖的 OAuth 端點網址和 CodeChallenge 物件。

下列程式碼範例說明如何建立驗證要求:

val request = OAuthRequest.Builder(this.applicationContext)
    .setAuthProviderUrl(Uri.parse("https://...."))
    .setClientId(clientId)
    .setCodeChallenge(codeChallenge)
    .build()

建構驗證要求後,使用 sendAuthorizationRequest() 方法將要求傳送至隨附應用程式:

val client = RemoteAuthClient.create(this)
client.sendAuthorizationRequest(request,
    { command -> command?.run() },
    object : RemoteAuthClient.Callback() {
        override fun onAuthorizationResponse(
            request: OAuthRequest,
            response: OAuthResponse
        ) {
            // Extract the token from the response, store it, and use it in
            // network requests.
        }

        override fun onAuthorizationError(errorCode: Int) {
            // Handle any errors.
        }
    }
)

這項要求會觸發對隨附應用程式的呼叫,在使用者的手機網路瀏覽器中顯示授權 UI。OAuth 2.0 提供者可以驗證使用者身分,並徵求使用者同意授予要求的權限。回應會傳送到自動產生的重新導向網址。

授權成功或失敗後,OAuth 2.0 伺服器會重新導向到要求中的指定網址。如果使用者核准了存取要求,回應內便會提供授權碼。如果使用者未核准要求,回應會包含錯誤訊息。

回應會以查詢字串的形式呈現,其範例如下:

  https://wear.googleapis.com/3p_auth/com.your.package.name?code=xyz
  https://wear.googleapis-cn.com/3p_auth/com.your.package.name?code=xyz

這個項目會載入頁面,將使用者導向至隨附應用程式,隨附應用程式會驗證回應網址,然後使用 onAuthorizationResponse API 將回應轉發給 Wear OS 應用程式。

隨後,手錶應用程式即可使用授權碼交換存取權杖。

裝置授權

使用「裝置授權許可」時,使用者會在另一台裝置上開啟驗證 URI。接著,驗證伺服器會要求使用者核准或拒絕要求。

如要簡化這項程序,可以使用 RemoteActivityHelper 在使用者的配對行動裝置上開啟網頁,如以下範例所示:

// Request access from the authorization server and receive Device Authorization
// Response.
val verificationUri = "..." // Extracted from the Device Authorization Response.
RemoteActivityHelper.startRemoteActivity(
    this,
    Intent(Intent.ACTION_VIEW)
        .addCategory(Intent.CATEGORY_BROWSABLE)
        .setData(Uri.parse(verificationUri)),
    null
)
// Poll the authorization server to find out if the user completed the user
// authorization step on their mobile device.

如果您使用 iOS 應用程式,請利用通用連結攔截應用程式意圖,不要使用瀏覽器驗證權杖。

改用舊版「使用 Google 帳戶登入」以外的服務

Credential Manager 設有「使用 Google 帳戶登入」按鈕的專屬整合點。先前,這個按鈕可新增至應用程式驗證 UX 的任何位置,但隨著按鈕納入憑證管理工具,舊版選項現已淘汰。

// Define a basic SDK check.
fun isCredentialManagerAvailable(): Boolean {
 return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM
}

// Elsewhere in the code, use it to selectively disable the legacy option.
Button(
  onClick = {
    if (isCredentialManagerAvailable()) {
      Log.w(TAG, "Devices on API level 35 or higher should use
                  Credential Manager for Sign in with Google")
    } else {
      navigateToSignInWithGoogle()
    }},
  enabled = !isCredentialManagerAvailable(),
  label = { Text(text = stringResource(R.string.sign_in_with_google)) },
  secondaryLabel = { Text(text = "Disabled on API level 35+")
  }
)