אימות באמצעות אפל באנדרואיד

אתה יכול לאפשר למשתמשים שלך לבצע אימות עם Firebase באמצעות Apple ID שלהם באמצעות Firebase SDK כדי לבצע את זרימת הכניסה מקצה לקצה OAuth 2.0.

לפני שאתה מתחיל

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

הצטרף לתוכנית המפתחים של אפל

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

הגדר כניסה עם אפל

באתר Apple Developer , בצע את הפעולות הבאות:

  1. שייך את האתר שלך לאפליקציה שלך כמתואר בסעיף הראשון של הגדר כניסה עם Apple לאינטרנט . כאשר תתבקש, רשום את כתובת האתר הבאה ככתובת URL להחזרה:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    אתה יכול לקבל את מזהה הפרויקט שלך ב-Firebase בדף ההגדרות של מסוף Firebase .

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

  2. צור כניסה עם מפתח פרטי של Apple . תזדקק למפתח הפרטי ומזהה המפתח החדש שלך בסעיף הבא.
  3. אם אתה משתמש באחת מהתכונות של Firebase Authentication ששולחות אימיילים למשתמשים, כולל כניסה לקישור דוא"ל, אימות כתובת דוא"ל, ביטול שינוי חשבון ואחרות, הגדר את שירות ממסר הדוא"ל הפרטי של Apple והירשם noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (או דומיין תבנית הדוא"ל המותאם אישית שלך) כך שאפל תוכל להעביר הודעות דוא"ל שנשלחות על ידי אימות Firebase לכתובות דוא"ל אנונימיות של Apple.

אפשר את Apple כספק כניסה

  1. הוסף את Firebase לפרויקט Android שלך . הקפד לרשום את חתימת ה-SHA-1 של האפליקציה שלך כאשר אתה מגדיר את האפליקציה שלך במסוף Firebase.
  2. במסוף Firebase , פתח את הקטע Auth . בכרטיסייה שיטת כניסה , הפעל את ספק Apple . ציין את מזהה השירות שיצרת בסעיף הקודם. כמו כן, בסעיף תצורת זרימת קוד OAuth , ציין את מזהה צוות Apple שלך ​​ואת המפתח הפרטי והמפתח שיצרת בסעיף הקודם.

עמוד בדרישות הנתונים האנונימיים של Apple

כניסה עם אפל נותנת למשתמשים אפשרות להפוך את הנתונים שלהם לאנונימיים, כולל כתובת הדוא"ל שלהם, בעת הכניסה. למשתמשים שבוחרים באפשרות זו יש כתובות דוא"ל עם הדומיין privaterelay.appleid.com . כאשר אתה משתמש בכניסה עם Apple באפליקציה שלך, עליך לציית לכל מדיניות מפתחים או תנאים רלוונטיים של Apple לגבי מזהי Apple אנונימיים אלה.

זה כולל קבלת כל הסכמת משתמש נדרשת לפני שאתה משייך מידע אישי מזהה ישיר עם מזהה Apple אנונימי. בעת שימוש באימות Firebase, זה עשוי לכלול את הפעולות הבאות:

  • קשר כתובת אימייל למזהה Apple אנונימי או להיפך.
  • קשר מספר טלפון למזהה Apple אנונימי או להיפך
  • קשר אישור חברתי לא אנונימי (פייסבוק, גוגל וכו') למזהה Apple אנונימי או להיפך.

הרשימה לעיל אינה ממצה. עיין בהסכם הרישיון של Apple Developer Program בסעיף החברות בחשבון המפתח שלך כדי לוודא שהאפליקציה שלך עומדת בדרישות של Apple.

טפל בזרימת הכניסה עם Firebase SDK

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

כדי לטפל בזרימת הכניסה עם Firebase Android SDK, בצע את השלבים הבאים:

  1. בנו מופע של OAuthProvider באמצעות ה-Builder שלו עם מזהה הספק apple.com :

    Kotlin+KTX

    val provider = OAuthProvider.newBuilder("apple.com")
    

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    
  2. אופציונלי: ציין היקפי OAuth 2.0 נוספים מעבר לברירת המחדל שברצונך לבקש מספק האימות.

    Kotlin+KTX

    provider.setScopes(arrayOf("email", "name"))
    

    Java

    List<String> scopes =
        new ArrayList<String>() {
          {
            add("email");
            add("name");
          }
        };
    provider.setScopes(scopes);
    

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

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

    Kotlin+KTX

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr")
    

    Java

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr");
    
  4. בצע אימות עם Firebase באמצעות אובייקט ספק OAuth. שים לב שבניגוד לפעולות אחרות FirebaseAuth , זה ישתלט על ממשק המשתמש שלך על ידי פתיחת כרטיסיית Chrome מותאמת אישית. כתוצאה מכך, אל תתייחס לפעילות שלך ב- OnSuccessListener וב- OnFailureListener שאתה מצרף מכיוון שהם יתנתקו מיד כשהפעולה תתחיל את ממשק המשתמש.

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

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

    Kotlin+KTX

    val pending = auth.pendingAuthResult
    if (pending != null) {
        pending.addOnSuccessListener { authResult ->
            Log.d(TAG, "checkPending:onSuccess:$authResult")
            // Get the user profile with authResult.getUser() and
            // authResult.getAdditionalUserInfo(), and the ID
            // token from Apple with authResult.getCredential().
        }.addOnFailureListener { e ->
            Log.w(TAG, "checkPending:onFailure", e)
        }
    } else {
        Log.d(TAG, "pending: null")
    }
    

    Java

    mAuth = FirebaseAuth.getInstance();
    Task<AuthResult> pending = mAuth.getPendingAuthResult();
    if (pending != null) {
        pending.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                Log.d(TAG, "checkPending:onSuccess:" + authResult);
                // Get the user profile with authResult.getUser() and
                // authResult.getAdditionalUserInfo(), and the ID
                // token from Apple with authResult.getCredential().
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "checkPending:onFailure", e);
            }
        });
    } else {
        Log.d(TAG, "pending: null");
    }
    

    אם אין תוצאה ממתינה, התחל את זרימת הכניסה, על ידי קריאה ל- startActivityForSignInWithProvider() :

    Kotlin+KTX

    auth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener { authResult ->
                // Sign-in successful!
                Log.d(TAG, "activitySignIn:onSuccess:${authResult.user}")
                val user = authResult.user
                // ...
            }
            .addOnFailureListener { e ->
                Log.w(TAG, "activitySignIn:onFailure", e)
            }
    

    Java

    mAuth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Sign-in successful!
                            Log.d(TAG, "activitySignIn:onSuccess:" + authResult.getUser());
                            FirebaseUser user = authResult.getUser();
                            // ...
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Log.w(TAG, "activitySignIn:onFailure", e);
                        }
                    });
    

    בניגוד לספקים אחרים הנתמכים על ידי Firebase Auth, אפל לא מספקת כתובת URL של תמונה.

    כמו כן, כאשר המשתמש בוחר שלא לשתף את הדוא"ל שלו עם האפליקציה, אפל מספקת כתובת דוא"ל ייחודית עבור אותו משתמש (בצורה xyz@privaterelay.appleid.com ), אותה היא חולקת עם האפליקציה שלך. אם הגדרת את שירות ממסר הדוא"ל הפרטי, אפל מעבירה מיילים שנשלחו לכתובת האנונימית לכתובת הדוא"ל האמיתית של המשתמש.

    Apple משתפת רק מידע משתמש כגון שם התצוגה עם יישומים בפעם הראשונה שמשתמש נכנס. בדרך כלל, Firebase מאחסן את שם התצוגה בפעם הראשונה שמשתמש נכנס ל-Apple, אותו תוכל לקבל באמצעות getCurrentUser().getDisplayName() . עם זאת, אם השתמשת בעבר ב-Apple כדי להיכנס משתמש לאפליקציה מבלי להשתמש ב-Firebase, Apple לא תספק ל-Firebase את שם התצוגה של המשתמש.

אימות מחדש וקישור חשבון

ניתן להשתמש באותה דפוס עם startActivityForReauthenticateWithProvider() שבו אתה יכול להשתמש כדי לאחזר אישור חדש עבור פעולות רגישות הדורשות כניסה אחרונה:

Kotlin+KTX

// The user is already signed-in.
val firebaseUser = auth.getCurrentUser()

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener( 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( e -> {
        // Handle failure.
    })

Java

// The user is already signed-in.
FirebaseUser firebaseUser = mAuth.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.
          }
        });

בנוסף, אתה יכול להשתמש linkWithCredential() כדי לקשר ספקי זהות שונים לחשבונות קיימים.

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

לדוגמה, כדי לקשר חשבון פייסבוק לחשבון Firebase הנוכחי, השתמש באסימון הגישה שקיבלת מהכניסה של המשתמש לפייסבוק:

Kotlin+KTX

// Initialize a Facebook credential with a Facebook access token.
val credential = FacebookAuthProvider.getCredential(token.getToken())

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, task -> {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      });

Java

// Initialize a Facebook credential with a Facebook access token.
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
      @Override
      public void onComplete(@NonNull Task<AuthResult> task) {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      }
    });

מתקדם: טפל בזרימת הכניסה באופן ידני

אתה יכול גם לבצע אימות עם Firebase באמצעות חשבון Apple על ידי טיפול בזרימת הכניסה על ידי שימוש ב-Apple Sign-In JS SDK, בנייה ידנית של זרימת OAuth או על ידי שימוש בספריית OAuth כגון AppAuth .

  1. עבור כל בקשת כניסה, צור מחרוזת אקראית - "nonce" - שבה תשתמש כדי לוודא שאסימון הזיהוי שתקבל הוענק במיוחד בתגובה לבקשת האימות של האפליקציה שלך. שלב זה חשוב כדי למנוע התקפות חוזרות.

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

    Kotlin+KTX

    private fun generateNonce(length: Int): String {
        val generator = SecureRandom()
    
        val charsetDecoder = StandardCharsets.US_ASCII.newDecoder()
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE)
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE)
    
        val bytes = ByteArray(length)
        val inBuffer = ByteBuffer.wrap(bytes)
        val outBuffer = CharBuffer.allocate(length)
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes)
            inBuffer.rewind()
            charsetDecoder.reset()
            charsetDecoder.decode(inBuffer, outBuffer, false)
        }
        outBuffer.flip()
        return outBuffer.toString()
    }
    

    Java

    private String generateNonce(int length) {
        SecureRandom generator = new SecureRandom();
    
        CharsetDecoder charsetDecoder = StandardCharsets.US_ASCII.newDecoder();
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE);
    
        byte[] bytes = new byte[length];
        ByteBuffer inBuffer = ByteBuffer.wrap(bytes);
        CharBuffer outBuffer = CharBuffer.allocate(length);
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes);
            inBuffer.rewind();
            charsetDecoder.reset();
            charsetDecoder.decode(inBuffer, outBuffer, false);
        }
        outBuffer.flip();
        return outBuffer.toString();
    }
    

    לאחר מכן, קבל את ה-Hash SHA246 של ה-nonce כמחרוזת hex:

    Kotlin+KTX

    private fun sha256(s: String): String {
        val md = MessageDigest.getInstance("SHA-256")
        val digest = md.digest(s.toByteArray())
        val hash = StringBuilder()
        for (c in digest) {
            hash.append(String.format("%02x", c))
        }
        return hash.toString()
    }
    

    Java

    private String sha256(String s) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(s.getBytes());
        StringBuilder hash = new StringBuilder();
        for (byte c: digest) {
            hash.append(String.format("%02x", c));
        }
        return hash.toString();
    }
    

    אתה תשלח את ה-hash SHA256 של nonce עם בקשת הכניסה שלך, שאפל תעביר ללא שינוי בתגובה. Firebase מאמת את התגובה על ידי hashing של ה-nonce המקורי והשוואתה לערך שהעביר אפל.

  2. התחל את זרימת הכניסה של Apple באמצעות ספריית OAuth שלך או שיטה אחרת. הקפד לכלול את ה-hash nonce כפרמטר בבקשה שלך.

  3. לאחר שתקבל את התגובה של אפל, קבל את אסימון המזהה מהתגובה והשתמש בו ובאי-גיבוב ללא גיבוב כדי ליצור AuthCredential :

    Kotlin+KTX

    val credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build()
    

    Java

    AuthCredential credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build();
    
  4. בצע אימות באמצעות Firebase באמצעות האישורים של Firebase:

    Kotlin+KTX

    auth.signInWithCredential(credential)
          .addOnCompleteListener(this) { task ->
              if (task.isSuccessful) {
                // User successfully signed in with Apple ID token.
                // ...
              }
          }
    

    Java

    mAuth.signInWithCredential(credential)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
          @Override
          public void onComplete(@NonNull Task<AuthResult> task) {
            if (task.isSuccessful()) {
              // User successfully signed in with Apple ID token.
              // ...
            }
          }
        });
    

אם הקריאה ל- signInWithCredential מצליחה, תוכל להשתמש בשיטת getCurrentUser כדי לקבל את נתוני החשבון של המשתמש.

ביטול אסימון

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

בנוסף, אפליקציות התומכות בכניסה עם אפל צריכות להשתמש ב- Sign in with Apple REST API כדי לבטל אסימוני משתמש.

כדי לעמוד בדרישה זו, יש ליישם את השלבים הבאים:

  1. השתמש בשיטת startActivityForSignInWithProvider() כדי להיכנס באמצעות Apple ולהשיג AuthResult .

  2. השג את אסימון הגישה לספק אפל.

    Kotlin+KTX

    val oauthCredential: OAuthCredential =  authResult.credential
    val accessToken = oauthCredential.accessToken
    

    Java

    OAuthCredential oauthCredential = (OAuthCredential) authResult.getCredential();
    String accessToken = oauthCredential.getAccessToken();
    
  3. בטל את האסימון באמצעות API של revokeAccessToken .

    Kotlin+KTX

    mAuth.revokeAccessToken(accessToken)
      .addOnCompleteListener(this) { task ->
        if (task.isSuccessful) {
          // Access token successfully revoked
          // for the user ...
        }
    }
    

    Java

    mAuth.revokeAccessToken(accessToken)
        .addOnCompleteListener(this, new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
              if (task.isSuccessful()) {
                // Access token successfully revoked
                // for the user ...
              }
            }
      });
    
  1. לבסוף, מחק את חשבון המשתמש (וכל הנתונים המשויכים)

    הצעדים הבאים

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

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

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

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

    כדי לצאת ממשתמש, התקשר ל- signOut :

    Kotlin+KTX

    Firebase.auth.signOut()

    Java

    FirebaseAuth.getInstance().signOut();