אימות עם Firebase באמצעות חשבונות מבוססי-סיסמה עם C++

ניתן להשתמש ב-Firebase Authentication כדי לאפשר למשתמשים לבצע אימות באמצעות Firebase באמצעות כתובות האימייל והסיסמאות שלהם, וכדי לנהל את שמבוססים על סיסמאות.

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

  1. מוסיפים את Firebase לפרויקט C++.
  2. אם עדיין לא קישרתם את האפליקציה לפרויקט Firebase, צריך לעשות זאת דרך מסוף Firebase.
  3. מפעילים את הכניסה באמצעות אימייל/סיסמה:
    1. במסוף Firebase, פותחים את בקטע אימות.
    2. בכרטיסייה שיטת כניסה, מפעילים את הכניסה אימייל/סיסמה ולוחצים על Save.

גישה לכיתה firebase::auth::Auth

המחלקה Auth היא השער לכל הקריאות ל-API.
  1. מוסיפים את קובצי הכותרות של Auth ו-App:
    #include "firebase/app.h"
    #include "firebase/auth.h"
    
  2. בקוד האתחול, יוצרים firebase::App.
    #if defined(__ANDROID__)
      firebase::App* app =
          firebase::App::Create(firebase::AppOptions(), my_jni_env, my_activity);
    #else
      firebase::App* app = firebase::App::Create(firebase::AppOptions());
    #endif  // defined(__ANDROID__)
    
  3. עליך להשיג את הכיתה firebase::auth::Auth ל-firebase::App. יש מיפוי אחד לאחד בין App לבין Auth.
    firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app);
    

יצירת חשבון שמבוסס על סיסמה

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

  1. כשמשתמש חדש נרשם באמצעות טופס ההרשמה של האפליקציה, צריך למלא שלבים לאימות החשבון שהאפליקציה דורשת, כמו אימות הסיסמה של החשבון החדש הוקלדה בצורה נכונה והיא עומדת במורכבות שלה בדרישות שלנו.
  2. ליצור חשבון חדש על ידי העברת כתובת האימייל והסיסמה של המשתמש החדש אל Auth::CreateUserWithEmailAndPassword:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->CreateUserWithEmailAndPassword(email, password);
    
  3. אם לתוכנית יש לולאת עדכון שרצה באופן קבוע (למשל ב-30 או ב-60) פעמים בשנייה), אפשר לבדוק את התוצאות פעם אחת בכל עדכון Auth::CreateUserWithEmailAndPasswordLastResult:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->CreateUserWithEmailAndPasswordLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        const firebase::auth::AuthResult auth_result = *result.result();
        printf("Create user succeeded for email %s\n",
               auth_result.user.email().c_str());
      } else {
        printf("Created user failed with error '%s'\n", result.error_message());
      }
    }
    
    לחלופין, אם התוכנית מבוססת על אירועים, ייתכן שתעדיפו לרשום קריאה חוזרת העתידי.

כניסה של משתמש באמצעות כתובת אימייל וסיסמה

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

  1. כשמשתמש נכנס לאפליקציה שלכם, מעבירים את כתובת האימייל שלו ו סיסמה אל firebase::auth::Auth::SignInWithEmailAndPassword:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInWithEmailAndPassword(email, password);
    
  2. אם לתוכנית יש לולאת עדכון שפועלת באופן קבוע (למשל 30 או 60 פעמים לשנייה), אפשר לבדוק את התוצאות פעם אחת בכל עדכון באמצעות Auth::SignInWithEmailAndPasswordLastResult:
    firebase::Future<firebase::auth::AuthResult> result =
        auth->SignInWithEmailAndPasswordLastResult();
    if (result.status() == firebase::kFutureStatusComplete) {
      if (result.error() == firebase::auth::kAuthErrorNone) {
        const firebase::auth::AuthResult auth_result = *result.result();
        printf("Sign in succeeded for email %s\n",
               auth_result.user.email().c_str());
      } else {
        printf("Sign in failed with error '%s'\n", result.error_message());
      }
    }
    
    לחלופין, אם התוכנית מונעת על ידי אירועים, עדיף לרשום קריאה חוזרת (callback) ל-Future.

רישום קריאה חוזרת (callback) בעתיד

בתוכנות מסוימות יש פונקציות Update שנקראות 30 או 60 פעמים בשנייה. לדוגמה, יש הרבה משחקים שמבוססים על המודל הזה. התוכניות האלה יכולות לקרוא לLastResult לדגום קריאות אסינכרוניות. עם זאת, אם התוכנית שלכם מבוססת על אירועים, יכול להיות שתעדיפו לרשום פונקציות קריאה חוזרת (callback). פונקציית הקריאה החוזרת מופעלת בסיום ה-Future.
void OnCreateCallback(const firebase::Future<firebase::auth::User*>& result,
                      void* user_data) {
  // The callback is called when the Future enters the `complete` state.
  assert(result.status() == firebase::kFutureStatusComplete);

  // Use `user_data` to pass-in program context, if you like.
  MyProgramContext* program_context = static_cast<MyProgramContext*>(user_data);

  // Important to handle both success and failure situations.
  if (result.error() == firebase::auth::kAuthErrorNone) {
    firebase::auth::User* user = *result.result();
    printf("Create user succeeded for email %s\n", user->email().c_str());

    // Perform other actions on User, if you like.
    firebase::auth::User::UserProfile profile;
    profile.display_name = program_context->display_name;
    user->UpdateUserProfile(profile);

  } else {
    printf("Created user failed with error '%s'\n", result.error_message());
  }
}

void CreateUser(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // `&my_program_context` is passed verbatim to OnCreateCallback().
  result.OnCompletion(OnCreateCallback, &my_program_context);
}
אם אתם מעדיפים, פונקציית הקריאה החוזרת יכולה גם להיות lambda.
void CreateUserUsingLambda(firebase::auth::Auth* auth) {
  // Callbacks work the same for any firebase::Future.
  firebase::Future<firebase::auth::AuthResult> result =
      auth->CreateUserWithEmailAndPasswordLastResult();

  // The lambda has the same signature as the callback function.
  result.OnCompletion(
      [](const firebase::Future<firebase::auth::User*>& result,
         void* user_data) {
        // `user_data` is the same as &my_program_context, below.
        // Note that we can't capture this value in the [] because std::function
        // is not supported by our minimum compiler spec (which is pre C++11).
        MyProgramContext* program_context =
            static_cast<MyProgramContext*>(user_data);

        // Process create user result...
        (void)program_context;
      },
      &my_program_context);
}

מומלץ: הפעלת הגנה על ספירת אימיילים

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

כדי למזער את הסיכון הזה, מומלץ להפעיל הגנה על ספירת אימיילים. לפרויקט באמצעות הכלי gcloud של Google Cloud. שימו לב שההפעלה של התכונה משנה את אופן הדיווח על שגיאות של Firebase Authentication: צריך לוודא שהאפליקציה לא מסתמכת על השגיאות הספציפיות יותר.

השלבים הבאים

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

  • באפליקציות שלכם, תוכלו לקבל את פרטי הפרופיל הבסיסיים של המשתמש דרך אובייקט firebase::auth::User:

    firebase::auth::User user = auth->current_user();
    if (user.is_valid()) {
      std::string name = user.display_name();
      std::string email = user.email();
      std::string photo_url = user.photo_url();
      // The user's ID, unique to the Firebase project.
      // Do NOT use this value to authenticate with your backend server,
      // if you have one. Use firebase::auth::User::Token() instead.
      std::string uid = user.uid();
    }
    
  • בתוך Firebase Realtime Database ו-Cloud Storage כללי אבטחה – מקבלים את מזהה המשתמש הייחודי של המשתמש המחובר מהמשתנה auth, ולהשתמש בהם כדי לקבוע לאילו נתונים המשתמש יוכל לגשת.

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

כדי לנתק משתמש מהחשבון, יש להתקשר אל SignOut():

auth->SignOut();