אימות באמצעות OpenID Connect ב-Android

אם שדרגתם ל-Firebase Authentication with Identity Platform, תוכלו לאמת את המשתמשים ב-Firebase באמצעות הספק התואם ל-OpenID Connect ‏ (OIDC) שבחרתם. כך תוכלו להשתמש בספקי זהויות שלא נתמכים באופן מקורי ב-Firebase.

לפני שמתחילים

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

  • מזהה לקוח: מחרוזת ייחודית לספק שמזהה את האפליקציה. יכול להיות שהספק יקצה לכם מזהה לקוח שונה לכל פלטפורמה שאתם תומכים בה. זהו אחד מהערכים של ההצהרה aud באסימוני מזהה שהספק הנפיק.

  • סוד לקוח: מחרוזת סוד שדרכה הספק מאמת את הבעלות על מזהה לקוח. לכל מזהה לקוח צריך סוד לקוח תואם. (הערך הזה נדרש רק אם אתם משתמשים בתהליך קוד האימות, שמומלץ מאוד להשתמש בו).

  • Issuer: מחרוזת שמזהה את הספק. הערך הזה חייב להיות כתובת URL, שמצורפת אליה /.well-known/openid-configuration, והיא המיקום של מסמך הגילוי של OIDC של הספק. לדוגמה, אם המנפיק הוא https://auth.example.com, מסמך הגילוי צריך להיות זמין בכתובת https://auth.example.com/.well-known/openid-configuration.

אחרי שמקבלים את המידע שלמעלה, מפעילים את OpenID Connect כספק כניסה לפרויקט ב-Firebase:

  1. מוסיפים את Firebase לפרויקט Android.

  2. אם עדיין לא שדרגתם ל-Firebase Authentication with Identity Platform, עליכם לעשות זאת. אימות OpenID Connect זמין רק בפרויקטים משודרגים.

  3. בדף Sign-in providers במסוף Firebase, לוחצים על Add new provider ואז על OpenID Connect.

  4. בוחרים אם להשתמש בתהליך קוד ההרשאה או בתהליך הענקת ההרשאה המרומזת.

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

  5. נותנים שם לספק. שימו לב למזהה הספק שנוצר: oidc.example-provider. תצטרכו את המזהה הזה כשתוסיפו לאפליקציה קוד כניסה.

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

  7. שומרים את השינויים.

טיפול בתהליך הכניסה באמצעות Firebase SDK

אם אתם מפתחים אפליקציה ל-Android, הדרך הקלה ביותר לאמת את המשתמשים ב-Firebase באמצעות ספק ה-OIDC היא לטפל בתהליך הכניסה כולו באמצעות Firebase Android SDK.

כדי לטפל בתהליך הכניסה באמצעות Firebase Android SDK:

  1. יצירה של מופע של OAuthProvider באמצעות Builder שלו עם מזהה הספק

    Kotlin

    val providerBuilder = OAuthProvider.newBuilder("oidc.example-provider")

    Java

    OAuthProvider.Builder providerBuilder = OAuthProvider.newBuilder("oidc.example-provider");

  2. אופציונלי: מציינים פרמטרים מותאמים אישית נוספים של OAuth שרוצים לשלוח עם בקשת ה-OAuth.

    Kotlin

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com")

    Java

    // Target specific email with login hint.
    providerBuilder.addCustomParameter("login_hint", "user@example.com");

    בודקים אילו פרמטרים נתמכים על ידי ספק ה-OIDC. שימו לב: אי אפשר להעביר פרמטרים שנדרשים ל-Firebase באמצעות setCustomParameters(). הפרמטרים האלה הם client_id,‏ response_type, ‏ redirect_uri, ‏ state, ‏ scope ו-response_mode.

  3. אופציונלי: מציינים היקפי הרשאות נוספים של OAuth 2.0, מעבר לפרופיל הבסיסי, שרוצים לבקש מספק האימות.

    Kotlin

    // Request read access to a user's email addresses.
    // This must be preconfigured in the app's API permissions.
    providerBuilder.scopes = listOf("mail.read", "calendars.read")

    Java

    // Request read access to a user's email addresses.
    // This must be preconfigured in the app's API permissions.
    List<String> scopes =
            new ArrayList<String>() {
                {
                    add("mail.read");
                    add("calendars.read");
                }
            };
    providerBuilder.setScopes(scopes);

    בודקים אילו היקפי הרשאה זמינים אצל ספק ה-OIDC.

  4. אימות באמצעות Firebase באמצעות אובייקט הספק של OAuth. חשוב לזכור שבניגוד לפעולות אחרות של FirebaseAuth, הפעולה הזו תשלוט בממשק המשתמש על ידי הצגת כרטיסייה מותאמת אישית ב-Chrome. לכן, אל תתייחסו לפעילות שלכם ב-OnSuccessListener וב-OnFailureListener שאתם מצרפים, כי הם ינותק מיד כשהפעולה תפעיל את ממשק המשתמש.

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

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

    Kotlin

    val pendingResultTask = firebaseAuth.pendingAuthResult
    if (pendingResultTask != null) {
        // There's something already here! Finish the sign-in for your user.
        pendingResultTask
            .addOnSuccessListener {
                // User is signed in.
                // IdP data available in
                // authResult.getAdditionalUserInfo().getProfile().
                // The OAuth access token can also be retrieved:
                // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                // The OAuth secret can be retrieved by calling:
                // ((OAuthCredential)authResult.getCredential()).getSecret().
            }
            .addOnFailureListener {
                // Handle failure.
            }
    } else {
        // There's no pending result so you need to start the sign-in flow.
        // See below.
    }

    Java

    Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
    if (pendingResultTask != null) {
        // There's something already here! Finish the sign-in for your user.
        pendingResultTask
                .addOnSuccessListener(
                        new OnSuccessListener<AuthResult>() {
                            @Override
                            public void onSuccess(AuthResult authResult) {
                                // User is signed in.
                                // IdP data available in
                                // authResult.getAdditionalUserInfo().getProfile().
                                // The OAuth access token can also be retrieved:
                                // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                                // The OAuth secret can be retrieved by calling:
                                // ((OAuthCredential)authResult.getCredential()).getSecret().
                            }
                        })
                .addOnFailureListener(
                        new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                // Handle failure.
                            }
                        });
    } else {
        // There's no pending result so you need to start the sign-in flow.
        // See below.
    }

    כדי להתחיל את תהליך הכניסה, צריך לבצע קריאה ל-startActivityForSignInWithProvider:

    Kotlin

    firebaseAuth
        .startActivityForSignInWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // User is signed in.
            // IdP data available in
            // authResult.getAdditionalUserInfo().getProfile().
            // The OAuth access token can also be retrieved:
            // ((OAuthCredential)authResult.getCredential()).getAccessToken().
            // The OAuth secret can be retrieved by calling:
            // ((OAuthCredential)authResult.getCredential()).getSecret().
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    firebaseAuth
            .startActivityForSignInWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // User is signed in.
                            // IdP data available in
                            // authResult.getAdditionalUserInfo().getProfile().
                            // The OAuth access token can also be retrieved:
                            // ((OAuthCredential)authResult.getCredential()).getAccessToken().
                            // The OAuth secret can be retrieved by calling:
                            // ((OAuthCredential)authResult.getCredential()).getSecret().
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

  5. הדוגמאות שלמעלה מתמקדות בתהליכי כניסה, אבל אפשר גם לקשר ספק OIDC למשתמש קיים באמצעות startActivityForLinkWithProvider. לדוגמה, אפשר לקשר כמה ספקים לאותו משתמש ולאפשר לו להיכנס באמצעות כל אחד מהם.

    Kotlin

    // The user is already signed-in.
    val firebaseUser = firebaseAuth.currentUser!!
    firebaseUser
        .startActivityForLinkWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // Provider credential is linked to the current user.
            // IdP data available in
            // authResult.getAdditionalUserInfo().getProfile().
            // The OAuth access token can also be retrieved:
            // authResult.getCredential().getAccessToken().
            // The OAuth secret can be retrieved by calling:
            // authResult.getCredential().getSecret().
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
    
    firebaseUser
            .startActivityForLinkWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Provider credential is linked to the current user.
                            // IdP data available in
                            // authResult.getAdditionalUserInfo().getProfile().
                            // The OAuth access token can also be retrieved:
                            // authResult.getCredential().getAccessToken().
                            // The OAuth secret can be retrieved by calling:
                            // authResult.getCredential().getSecret().
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

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

    Kotlin

    // The user is already signed-in.
    val firebaseUser = firebaseAuth.currentUser!!
    firebaseUser
        .startActivityForReauthenticateWithProvider(activity, provider.build())
        .addOnSuccessListener {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
        }
        .addOnFailureListener {
            // Handle failure.
        }

    Java

    // The user is already signed-in.
    FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
    
    firebaseUser
            .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // User is re-authenticated with fresh tokens and
                            // should be able to perform sensitive operations
                            // like account deletion and email or password
                            // update.
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            // Handle failure.
                        }
                    });

טיפול בתהליך הכניסה באופן ידני

אם כבר הטמעתם את תהליך הכניסה של OpenID Connect באפליקציה, תוכלו להשתמש באסימון המזהה ישירות כדי לבצע אימות באמצעות Firebase:

Kotlin

val providerId = "oidc.example-provider" // As registered in Firebase console.
val credential = oAuthCredential(providerId) {
    setIdToken(idToken) // ID token from OpenID Connect flow.
}
Firebase.auth
    .signInWithCredential(credential)
    .addOnSuccessListener { authResult ->
        // User is signed in.

        // IdP data available in:
        //    authResult.additionalUserInfo.profile
    }
    .addOnFailureListener { e ->
        // Handle failure.
    }

Java

AuthCredential credential = OAuthProvider
        .newCredentialBuilder("oidc.example-provider")  // As registered in Firebase console.
        .setIdToken(idToken)  // ID token from OpenID Connect flow.
        .build();
FirebaseAuth.getInstance()
        .signInWithCredential(credential)
        .addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                // User is signed in.

                // IdP data available in:
                //    authResult.getAdditionalUserInfo().getProfile()
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Handle failure.
            }
        });

השלבים הבאים

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

  • באפליקציות, אפשר לקבל את פרטי הפרופיל הבסיסיים של המשתמש מהאובייקט FirebaseUser. ניהול משתמשים

  • בכללי האבטחה של Firebase Realtime Database ו-Cloud Storage, אפשר לקבל את מזהה המשתמש הייחודי של המשתמש שנכנס לחשבון מהמשתנה auth, ולהשתמש בו כדי לקבוע לאילו נתונים למשתמש תהיה גישה.

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

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

Kotlin

Firebase.auth.signOut()

Java

FirebaseAuth.getInstance().signOut();