אימות בגאדג'טים לבישים: Credential Manager

אפליקציות ל-Wear OS יכולות לפעול באופן עצמאי, בלי אפליקציה נלווית. כלומר, אפליקציה ל-Wear OS צריכה לנהל את האימות בעצמה כשהיא ניגשת לנתונים מהאינטרנט. אבל הגודל הקטן של המסך בשעון והיכולות המצומצמות של הקלט מגבילים את אפשרויות האימות שאפליקציית Wear OS יכולה להשתמש בהן.

במדריך הזה מוסבר על השיטה המומלצת לאימות באפליקציות ל-Wear OS – Credential Manager (הכלי לניהול פרטי כניסה).

כדי לקבל מידע נוסף על עיצוב חוויית כניסה טובה, אפשר לעיין במדריך לחוויית משתמש בכניסה.

שיקולים ראשוניים

לפני שמתחילים בהטמעה, חשוב לקחת בחשבון את הנקודות הבאות.

מצב אורח

לא נדרש אימות לכל הפונקציות. במקום זאת, כדאי לספק למשתמש כמה שיותר תכונות בלי לדרוש ממנו להיכנס לחשבון.

יכול להיות שמשתמשים יגלו את אפליקציית Wear שלכם ויתקינו אותה בלי להשתמש באפליקציה לנייד, ולכן יכול להיות שלא יהיה להם חשבון והם לא ידעו אילו תכונות היא מציעה. חשוב לוודא שהפונקציונליות של מצב האורח מדגימה בצורה מדויקת את התכונות של האפליקציה.

יכול להיות שחלק מהמכשירים יישארו פתוחים למשך זמן ארוך יותר

במכשירים נתמכים שפועלת בהם מערכת Wear OS 5 ומעלה, המערכת מזהה אם המשתמש עונד את המכשיר על פרק כף היד. אם המשתמש משבית את זיהוי המכשיר על היד ואז מסיר את המכשיר מהיד, המערכת משאירה את המכשיר לא נעול למשך זמן ארוך יותר ממה שהיה קורה אחרת.

אם האפליקציה דורשת רמת אבטחה גבוהה יותר – למשל, כשמוצגים נתונים רגישים או פרטיים – צריך קודם לבדוק אם זיהוי המכשיר על היד מופעל:

val wristDetectionEnabled =
        isWristDetectionAutoLockingEnabled(applicationContext)

אם ערך ההחזרה של השיטה הזו הוא false, צריך להציג למשתמש בקשה להיכנס לחשבון באפליקציה לפני הצגת תוכן שספציפי למשתמש.

מנהל פרטי הכניסה

Credential Manager הוא ה-API המומלץ לאימות ב-Wear OS. היא מספקת סביבה מאובטחת יותר למשתמשים כדי להיכנס לאפליקציות של Wear OS בהגדרה עצמאית, בלי צורך בטלפון מחובר ומוצמד ובלי צורך לזכור את הסיסמה.

במסמך הזה מפורט המידע שמפתחים צריכים כדי להטמיע פתרון של Credential Manager עם מנגנוני האימות הרגילים שהוא מארח, שהם:

  • מפתחות גישה
  • סיסמאות
  • זהויות מאוחדות (כמו כניסה באמצעות חשבון Google)

במדריך הזה מוסבר גם איך להעביר את שיטות האימות האחרות המקובלות ב-WearOS (שיתוף אסימונים של שכבת הנתונים ו-OAuth) כגיבויים ל-Credential Manager, ואיך לטפל במעבר מהגרסה העצמאית של לחצן הכניסה באמצעות חשבון Google, שהוצאה משימוש, לגרסה המוטמעת של Credential Manager.

מפתחות גישה ב-Wear OS

מומלץ מאוד למפתחים להטמיע מפתחות גישה בהטמעות של מנהל פרטי הכניסה ב-Wear OS. מפתחות גישה הם הסטנדרט החדש בתחום לאימות משתמשי קצה, ויש להם כמה יתרונות משמעותיים למשתמשים.

מפתחות גישה הם דרך קלה יותר

  • המשתמשים יכולים לבחור חשבון כדי להיכנס איתו. הם לא צריכים להקליד שם משתמש.
  • המשתמשים יכולים לבצע אימות באמצעות שיטת פתיחת הנעילה של המסך במכשיר.
  • אחרי שיוצרים מפתח גישה ורושמים אותו, המשתמש יכול לעבור בקלות למכשיר חדש ולהשתמש בו באופן מיידי בלי צורך לרשום אותו מחדש.

מפתחות גישה הם בטוחים יותר

  • המפתחים שומרים בשרת רק מפתח ציבורי במקום סיסמה, ולכן לגורם זדוני יש הרבה פחות סיבות לפרוץ לשרתים, וגם אם מתרחש פריצה, יש הרבה פחות נתונים למחוק.
  • מפתחות גישה מספקים הגנה עמידה בפני פישינג. מפתחות גישה פועלים רק באתרים ובאפליקציות שבהם הם רשומים. אי אפשר להערים על משתמשים כדי שיאמתו את עצמם באתר מטעה, כי הדפדפן או מערכת ההפעלה מטפלים באימות.
  • מפתחות גישה מצמצמים את הצורך בשליחת SMS, וכך הופכים את האימות לחסכוני יותר.

הטמעה של מפתחות גישה

כולל הגדרה והנחיות לכל סוגי ההטמעה.

הגדרה

  1. מגדירים את רמת ה-API לטירגוט ל-35 בקובץ build.gradle של מודול האפליקציה:

    android {
        defaultConfig {
            targetSdkVersion(35)
        }
    }
    
  2. מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה או המודול, באמצעות הגרסה היציבה האחרונה מandroidx.credentials releases.

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

שיטות אימות מובנות

מכיוון ש-Credential Manager הוא API מאוחד, שלבי ההטמעה ב-Wear OS זהים לאלה של כל סוג אחר של מכשיר.

כדי להתחיל ולהטמיע תמיכה במפתחות גישה ובסיסמאות, אפשר להיעזר בהוראות לנייד.

השלבים להוספת תמיכה בכניסה באמצעות חשבון Google ל'מנהל פרטי הכניסה' מיועדים לפיתוח לנייד, אבל הם זהים ב-Wear OS. בקטע מעבר מגרסה קודמת של 'כניסה באמצעות חשבון Google' מפורטים שיקולים מיוחדים למקרה הזה.

שימו לב: אי אפשר ליצור פרטי כניסה ב-Wear OS, ולכן לא צריך להטמיע את השיטות ליצירת פרטי כניסה שמפורטות בהוראות לנייד.

שיטות אימות לגיבוי

יש עוד שתי שיטות אימות מקובלות לאפליקציות ל-WearOS: ‏ OAuth 2.0 (כל אחת מהגרסאות) ושיתוף של נתונים של אסימוני אימות לנייד בשכבת נתונים. למרות שלשיטות האלה אין נקודות שילוב ב-Credential Manager API, אפשר לכלול אותן בתהליך חוויית המשתמש של Credential Manager כחלופות למקרה שהמשתמשים יסגרו את המסך של Credential Manager.

כדי לטפל בפעולת המשתמש של סגירת המסך של כלי ניהול פרטי הכניסה, צריך ללכוד את NoCredentialException כחלק מהלוגיקה של GetCredential ולנווט לממשק המשתמש המותאם אישית של האימות.

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

לאחר מכן, ממשק המשתמש המותאם אישית של האימות יכול לספק כל אחת משיטות האימות המקובלות האחרות שמתוארות במדריך לחוויית משתמש בתהליך הכניסה.

שיתוף טוקנים של שכבת נתונים

אפליקציית הטלפון הנלווית יכולה להעביר נתוני אימות בצורה מאובטחת לאפליקציה ל-Wear OS באמצעות Wearable Data Layer API. להעביר את פרטי הכניסה כהודעות או כפריטי נתונים.

בדרך כלל, סוג האימות הזה לא דורש פעולה כלשהי מהמשתמש. עם זאת, מומלץ להימנע מביצוע אימות בלי להודיע למשתמש שהוא נכנס לחשבון. אפשר להציג למשתמש מסך שאפשר לסגור, שבו מוסבר שהחשבון שלו מועבר מהנייד.

חשוב: באפליקציית Wear OS צריך להציע לפחות שיטת אימות נוספת, כי האפשרות הזו פועלת רק בשעונים שמזווגים ל-Android כשהאפליקציה התואמת לנייד מותקנת. צריך לספק שיטת אימות חלופית למשתמשים שלא התקינו את האפליקציה המתאימה לנייד או שהמכשיר שלהם עם Wear OS משויך למכשיר iOS.

מעבירים טוקנים באמצעות שכבת הנתונים מהאפליקציה לנייד, כמו בדוגמה הבאה:

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

למידע נוסף על השימוש בשכבת הנתונים של מכשירים לבישים, אפשר לקרוא את המאמר שליחה וסנכרון של נתונים ב-Wear OS.

שימוש ב-OAuth 2.0

מערכת Wear OS תומכת בשני תהליכים שמבוססים על OAuth 2.0, שמתוארים בסעיפים הבאים:

  • קוד הרשאה עם מפתח הוכחה להחלפת קוד (PKCE), כפי שמוגדר ב-RFC 7636
  • מתן הרשאה למכשיר (DAG), כפי שמוגדר ב-RFC 8628
מפתח הוכחה לחילופי קודים (PKCE)

כדי להשתמש ב-PKCE בצורה יעילה, צריך להשתמש ב-RemoteAuthClient. לאחר מכן, כדי לבצע בקשת אימות מהאפליקציה ל-Wear OS לספק OAuth, יוצרים אובייקט OAuthRequest. האובייקט הזה מורכב מכתובת URL לנקודת הקצה של 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.
        }
    }
)

הבקשה הזו מפעילה קריאה לאפליקציה הנלווית, שמציגה ממשק משתמש של הרשאה בדפדפן אינטרנט בטלפון הנייד של המשתמש. ספק OAuth 2.0 מאמת את המשתמש ומקבל את הסכמתו להרשאות המבוקשות. התשובה נשלחת לכתובת ה-URL להפניה אוטומטית שנוצרה.

אחרי אישור או דחייה של הרשאה, שרת OAuth 2.0 מפנה לכתובת ה-URL שצוינה בבקשה. אם המשתמש מאשר את בקשת הגישה, התשובה תכיל קוד הרשאה. אם המשתמש לא מאשר את הבקשה, התשובה מכילה הודעת שגיאה.

התשובה היא בצורה של מחרוזת שאילתה, והיא נראית כמו אחת מהדוגמאות הבאות:

  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

הפעולה הזו טוענת דף שמפנה את המשתמש לאפליקציה הנלווית. האפליקציה הנלווית מאמתת את כתובת ה-URL של התגובה ומעבירה את התגובה לאפליקציית Wear OS באמצעות onAuthorizationResponse API.

אחרי כן, אפליקציית השעון יכולה להחליף את קוד ההרשאה באסימון גישה.

Device Authorization Grant

כשמשתמשים בהרשאת גישה למכשיר, המשתמש פותח את ה-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'. בעבר, אפשר היה להוסיף את הלחצן הזה בכל מקום בממשק המשתמש של אימות האפליקציה, אבל עכשיו, אחרי שהוא נכלל במנהל האישורים, האפשרות הישנה הוצאה משימוש.

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