אימות באמצעות Apple באמצעות JavaScript

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

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

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

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

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

הגדרת הכניסה באמצעות Apple

ב-Apple אתר למפתחים, צריך לבצע את הפעולות הבאות:

  1. משייכים את האתר לאפליקציה כפי שמתואר בקטע הראשון של המאמר הגדרת 'כניסה באמצעות Apple' לאינטרנט. כשמוצגת בקשה, רושמים את כתובת ה-URL הבאה ככתובת 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 (או הדומיין של תבנית האימייל המותאמת אישית שלכם) כדי ש-Apple תוכל להעביר אימיילים שנשלחו. עד Firebase Authentication לכתובות אימייל אנונימיות של Apple.

הפעלת Apple כספק כניסה

  1. מוסיפים את Firebase לפרויקט.
  2. במסוף Firebase, פותחים את הקטע Auth. בכרטיסייה Sign in method מפעילים את הספק Apple. מציינים את מזהה השירות שיצרתם בקטע הקודם. כמו כן, קטע תצורה של זרימת קוד OAuth, מציין את המזהה של צוות Apple ואת המפתח הפרטי ומזהה המפתח שיצרתם בקטע הקודם.

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

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

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

  • קישור כתובת אימייל ל-Apple ID אנונימי או להפך.
  • קישור של מספר טלפון ל-Apple ID שהוסרה ממנו הפרטיות או להפך
  • לקשר פרטי כניסה לא אנונימיים ברשתות חברתיות (Facebook,‏ Google וכו') ל-Apple ID אנונימי, ולהפך.

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

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

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

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

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

    Web

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('apple.com');

    Web

    var provider = new firebase.auth.OAuthProvider('apple.com');
  2. אופציונלי: מציינים היקפי הרשאות נוספים של OAuth 2.0 מעבר להיקפי ברירת המחדל שרוצים לבקש מספק האימות.

    Web

    provider.addScope('email');
    provider.addScope('name');

    Web

    provider.addScope('email');
    provider.addScope('name');

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

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

    Web

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });

    Web

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });
  4. אימות באמצעות Firebase באמצעות אובייקט הספק של OAuth. אתם יכולים לבקש מהמשתמשים להיכנס באמצעות חשבונות Apple שלהם על ידי פתיחת חלון קופץ או על ידי הפניה לדף הכניסה. שיטת ההפניה האוטומטית היא במכשירים ניידים.

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

      Web

      import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
      
      const auth = getAuth();
      signInWithPopup(auth, provider)
        .then((result) => {
          // The signed-in user info.
          const user = result.user;
      
          // Apple credential
          const credential = OAuthProvider.credentialFromResult(result);
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
          // ...
        })
        .catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.customData.email;
          // The credential that was used.
          const credential = OAuthProvider.credentialFromError(error);
      
          // ...
        });

      Web

      firebase
        .auth()
        .signInWithPopup(provider)
        .then((result) => {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
      
          // The signed-in user info.
          var user = result.user;
      
          // You can also get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
        // ...
        })
        .catch((error) => {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });
    • כדי להיכנס באמצעות הפניה אוטומטית לדף הכניסה, קוראים לפונקציה signInWithRedirect():

    Web

    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);

    Web

    firebase.auth().signInWithRedirect(provider);

    אחרי שהמשתמש משלים את הכניסה ומוחזר לדף, אפשר לקבל את תוצאת הכניסה באמצעות קריאה ל-getRedirectResult():

    Web

    import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
    
    // Result from Redirect auth flow.
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        const credential = OAuthProvider.credentialFromResult(result);
        if (credential) {
          // You can also get the Apple OAuth Access and ID Tokens.
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
        }
        // The signed-in user info.
        const user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.customData.email;
        // The credential that was used.
        const credential = OAuthProvider.credentialFromError(error);
    
        // ...
      });

    Web

    // Result from Redirect auth flow.
    firebase
      .auth()
      .getRedirectResult()
      .then((result) => {
        if (result.credential) {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
    
          // You can get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
    
          // IdP data available in result.additionalUserInfo.profile.
          // ...
        }
        // The signed-in user info.
        var user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        // The email of the user's account used.
        var email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        var credential = error.credential;
    
        // ...
      });

    כאן אפשר גם לזהות ולטפל בשגיאות. רשימה של קודי השגיאה מופיעה בחומר העזר של ה-API.

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

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

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

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

אפשר להשתמש באותו דפוס עם reauthenticateWithPopup() ו-reauthenticateWithRedirect(), כדי לאחזר פרטי כניסה עדכניים לפעולות רגישות שדורשות כניסה לאחרונה:

Web

import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";

// Result from Redirect auth flow.
const auth = getAuth();
const provider = new OAuthProvider('apple.com');

reauthenticateWithPopup(auth.currentUser, provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.

    // The signed-in user info.
    const user = result.user;

    // You can also get the Apple OAuth Access and ID Tokens.
    const credential = OAuthProvider.credentialFromResult(result);
    const accessToken = credential.accessToken;
    const idToken = credential.idToken;

    // ...
  })
  .catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The credential that was used.
    const credential = OAuthProvider.credentialFromError(error);

    // ...
  });

Web

const provider = new firebase.auth.OAuthProvider('apple.com');

firebase
  .auth()
  .currentUser
  .reauthenticateWithPopup(provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.
    /** @type {firebase.auth.OAuthCredential} */
    var credential = result.credential;

    // The signed-in user info.
    var user = result.user;
     // You can also get the Apple OAuth Access and ID Tokens.
    var accessToken = credential.accessToken;
    var idToken = credential.idToken;

    // IdP data available in result.additionalUserInfo.profile.
      // ...
  })
  .catch((error) => {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // The email of the user's account used.
    var email = error.email;
    // The firebase.auth.AuthCredential type that was used.
    var credential = error.credential;

    // ...
  });

אפשר גם להשתמש ב-linkWithPopup() וב-linkWithRedirect() כדי לקשר ספקי זהויות שונים לחשבונות קיימים.

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

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

Web

import { getAuth, linkWithPopup, FacebookAuthProvider } from "firebase/auth";

const auth = getAuth();
const provider = new FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
linkWithPopup(auth.currentUser, provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // ...

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Web

const provider = new firebase.auth.FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
firebase.auth().currentUser.linkWithPopup(provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // Facebook additional data available in result.additionalUserInfo.profile,

      // Additional Facebook OAuth access token can also be retrieved.
      // result.credential.accessToken

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

אימות באמצעות Firebase בתוסף ל-Chrome

אם אתם בונים אפליקציית תוסף ל-Chrome, תוכלו לעיין ב מדריך לעבודה מחוץ למסך.

חשוב לזכור שעדיין צריך לאמת את הדומיין המותאם אישית מול Apple, בדומה לדומיין ברירת המחדל firebaseapp.com:

http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt

ביטול אסימון

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

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

  1. חשוב לוודא שמילאתם את הקטע Services ID ואת הקטע OAuth code flow configuration בהגדרות הספק של 'כניסה באמצעות Apple', כפי שמתואר בקטע הגדרת 'כניסה באמצעות Apple'.

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

    לאחר מכן, מקבלים את אסימון הגישה של Apple OAuth מה-OAuthCredential, ומשתמשים בו כדי לבצע קריאה ל-revokeAccessToken(auth, token) כדי לבטל את אסימון הגישה של Apple OAuth.

    const provider = new OAuthProvider('apple.com');
    provider.addScope('email');
    provider.addScope('name');
    
    const auth = getAuth();
    signInWithPopup(auth, provider).then(result => {
      // Get the Apple OAuth access token.
      const credential = OAuthProvider.credentialFromResult(result);
      const accessToken = credential.accessToken;
    
      // Revoke the Apple OAuth access token.
      revokeAccessToken(auth, accessToken)
        .then(() => {
          // Token revoked.
    
          // Delete the user account.
          // ...
        })
        .catch(error => {
          // An error happened.
          // ...
        });
    });
    
  3. לבסוף, מוחקים את חשבון המשתמש (ואת כל בנתונים משויכים).

מתקדם: אימות באמצעות Firebase ב-Node.js

כדי לבצע אימות באמצעות Firebase באפליקציה של Node.js:

  1. עליך להיכנס למשתמש באמצעות חשבון Apple שלו ולקבל את ה-Apple ID שלו ב-Assistant. ניתן לעשות זאת בכמה דרכים. לדוגמה, אם ב-Node.js לאפליקציה יש ממשק קצה של דפדפן:

    1. בקצה העורפי, יוצרים מחרוזת אקראית ('nonce') ומחשבים גיבוב (hash) מסוג SHA256. המזהה החד-פעמי הוא ערך לשימוש חד-פעמי שמשמש לאימות של נסיעה הלוך ושוב אחת בין הקצה העורפי שלכם לבין שרתי האימות של Apple.

      Web

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = (length) => {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        let nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');

      Web

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = function(length) {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        var nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');
    2. בדף הכניסה, מציינים את המחרוזת החד-פעמית (nonce) שעברה גיבוב בהגדרות של הכניסה באמצעות Apple:

      <script src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
      <div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
      <script>
          AppleID.auth.init({
              clientId: YOUR_APPLE_CLIENT_ID,
              scope: 'name email',
              redirectURI: URL_TO_YOUR_REDIRECT_HANDLER,  // See the next step.
              state: '[STATE]',  // Optional value that Apple will send back to you
                                 // so you can return users to the same context after
                                 // they sign in.
              nonce: HASHED_NONCE  // The hashed nonce you generated in the previous step.
          });
      </script>
      
    3. מקבלים את האסימון של Apple ID מתגובת השרת של אימות שבוצע:

      app.post('/redirect', (req, res) => {
        const savedState = req.cookies.__session;
        const code = req.body.code;
        const state = req.body.state;
        const appleIdToken = req.body.id_token;
        if (savedState !== state || !code) {
          res.status(403).send('403: Permission denied');
        } else {
          // Sign in with Firebase using appleIdToken. (See next step).
        }
      });
      

    כדאי לעיין גם בהגדרת דף האינטרנט לכניסה באמצעות Apple.

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

    Web

    import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    
    // Build Firebase credential with the Apple ID token.
    const provider = new OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    signInWithCredential(auth, authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

    Web

    // Build Firebase credential with the Apple ID token.
    const provider = new firebase.auth.OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    firebase.auth().signInWithCredential(authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

השלבים הבאים

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

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

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

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

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

Web

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

Web

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});