Check out what’s new from Firebase@ Google I/O 2021, and join our alpha program for early access to the new Remote Config personalization feature. Learn more

צור אסימונים בהתאמה אישית

Firebase נותן לך שליטה מלאה על האימות בכך שהוא מאפשר לאמת משתמשים או מכשירים באמצעות JSON Web Tokens (JWT) מאובטחים. אתה יוצר אסימונים אלה בשרת שלך, מעביר אותם בחזרה למכשיר לקוח ואז משתמש בהם לאימות באמצעות שיטת signInWithCustomToken() .

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

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

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

אסימונים מותאמים אישית הם JWT חתומים כאשר המפתח הפרטי המשמש לחתימה שייך לחשבון שירות של גוגל. ישנן מספר דרכים לציין את חשבון השירות של גוגל שיש להשתמש בו ב- SDK של Firebase Admin לחתימה על אסימונים מותאמים אישית:

  • שימוש בקובץ JSON של חשבון שירות - ניתן להשתמש בשיטה זו בכל סביבה, אך מחייב אותך לארוז קובץ JSON של חשבון שירות יחד עם הקוד שלך. יש לנקוט בזהירות מיוחדת בכדי להבטיח שקובץ JSON של חשבון השירות לא ייחשף לגורמים חיצוניים.
  • לתת ל- Admin SDK לגלות חשבון שירות - ניתן להשתמש בשיטה זו בסביבות המנוהלות על ידי גוגל כמו פונקציות Google Cloud ו- App Engine. ייתכן שיהיה עליך להגדיר מספר הרשאות נוספות באמצעות מסוף הענן של Google.
  • שימוש במזהה חשבון שירות - כאשר משתמשים בסביבה המנוהלת על ידי Google, שיטה זו תחתום על אסימונים באמצעות מפתח חשבון השירות שצוין. עם זאת, הוא משתמש בשירות אינטרנט מרוחק, וייתכן שתצטרך להגדיר הרשאות נוספות לחשבון שירות זה באמצעות מסוף הענן של Google.

באמצעות קובץ JSON של חשבון שירות

קבצי JSON של חשבון שירות מכילים את כל המידע המתאים לחשבונות שירות (כולל המפתח הפרטי RSA). ניתן להוריד אותם מקונסולת Firebase. עקוב אחר הוראות הגדרת מנהל מערכת SDK למידע נוסף על אופן אתחול ה- SDK של מנהל המערכת עם קובץ JSON של חשבון שירות.

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

מתן ל- SDK של מנהל המערכת לגלות חשבון שירות

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

  • אם הקוד שלך נפרס בסביבת התקן App Engine עבור Java, Python או Go, ה- Admin SDK יכול להשתמש בשירות App Identity הקיים בסביבה זו כדי לחתום על אסימונים מותאמים אישית. שירות זהות האפליקציה חותם על נתונים באמצעות חשבון שירות שמספק לאפליקציה שלך Google Engine Engine.

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

כדי להשתמש בשיטות חתימה אלה, אתחל את ה- SDK עם אישורי ברירת המחדל של יישום Google ואל תציין מחרוזת מזהה חשבון שירות:

Node.js

admin.initializeApp();

ג'אווה

FirebaseApp.initializeApp();

פִּיתוֹן

default_app = firebase_admin.initialize_app()

ללכת

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C #

FirebaseApp.Create();

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

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

בדיוק כמו עם מזהי חשבון שירות שצוינו במפורש, על מזהי חשבון שירות שגילו אוטומטית להיות iam.serviceAccounts.signBlob הרשאת iam.serviceAccounts.signBlob כדי שיצירת האסימון המותאם אישית תפעל. ייתכן שיהיה עליך להשתמש במקטע IAM ובניהול של Google Cloud Console כדי להעניק לחשבונות שירות ברירת המחדל את ההרשאות הדרושות. לקבלת פרטים נוספים, עיין בסעיף פתרון בעיות למטה.

באמצעות מזהה חשבון שירות

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

ניתן למצוא את מזהה חשבון השירות ב- Google Cloud Console , או בשדה client_email של קובץ JSON שהורד. מזהי חשבון שירות הם כתובות דוא"ל בפורמט הבא: <client-id>@<project-id>.iam.gserviceaccount.com . הם מזהים באופן ייחודי חשבונות שירות בפרויקטים של Firebase ו- Google Cloud.

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

Node.js

admin.initializeApp({
  serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});

ג'אווה

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
    .build();
FirebaseApp.initializeApp(options);

פִּיתוֹן

options = {
    'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)

ללכת

conf := &firebase.Config{
	ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C #

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
    ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});

תעודות מזהה של חשבון שירות אינן מידע רגיש ולכן חשיפתן אינה חשובה. עם זאת, כדי לחתום על אסימונים מותאמים אישית עם חשבון השירות שצוין, על ה- SDK של מנהל ה- Firebase להפעיל שירות מרוחק. יתר על כן, עליך לוודא כי חשבון השירות ש- SDK מנהל המערכת משתמש בו לצורך ביצוע שיחה זו - בדרך כלל {project-name}@appspot.gserviceaccount.com - הוא iam.serviceAccounts.signBlob הרשאת iam.serviceAccounts.signBlob . לקבלת פרטים נוספים, עיין בסעיף פתרון בעיות למטה.

צור אסימונים מותאמים אישית באמצעות Firebase Admin SDK

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

Node.js

const uid = 'some-uid';

admin
  .auth()
  .createCustomToken(uid)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

ג'אווה

String uid = "some-uid";

String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client

פִּיתוֹן

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

ללכת

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C #

var uid = "some-uid";

string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client

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

Node.js

const userId = 'some-uid';
const additionalClaims = {
  premiumAccount: true,
};

admin
  .auth()
  .createCustomToken(userId, additionalClaims)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

ג'אווה

String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);

String customToken = FirebaseAuth.getInstance()
    .createCustomToken(uid, additionalClaims);
// Send token back to client

פִּיתוֹן

uid = 'some-uid'
additional_claims = {
    'premiumAccount': True
}

custom_token = auth.create_custom_token(uid, additional_claims)

ללכת

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

claims := map[string]interface{}{
	"premiumAccount": true,
}

token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

C #

var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
    { "premiumAccount", true },
};

string customToken = await FirebaseAuth.DefaultInstance
    .CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client

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

לאחר שתיצור אסימון מותאם אישית, עליך לשלוח אותו לאפליקציית הלקוח שלך. אפליקציית הלקוח מאמתת באמצעות האסימון המותאם אישית על ידי קריאת signInWithCustomToken() :

iOS

מטרה-ג
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
מָהִיר
Auth.auth().signIn(withCustomToken: customToken ?? "") { (user, error) in
  // ...
}

דְמוּי אָדָם

mAuth.signInWithCustomToken(mCustomToken)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCustomToken:success");
                    FirebaseUser user = mAuth.getCurrentUser();
                    updateUI(user);
                } else {
                    // If sign in fails, display a message to the user.
                    Log.w(TAG, "signInWithCustomToken:failure", task.getException());
                    Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
                            Toast.LENGTH_SHORT).show();
                    updateUI(null);
                }
            }
        });

אַחְדוּת

auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
  if (task.IsCanceled) {
    Debug.LogError("SignInWithCustomTokenAsync was canceled.");
    return;
  }
  if (task.IsFaulted) {
    Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
    return;
  }

  Firebase.Auth.FirebaseUser newUser = task.Result;
  Debug.LogFormat("User signed in successfully: {0} ({1})",
      newUser.DisplayName, newUser.UserId);
});

C ++

firebase::Future<firebase::auth::User*> result =
    auth->SignInWithCustomToken(custom_token);

אינטרנט

firebase.auth().signInWithCustomToken(token)
  .then((userCredential) => {
    // Signed in
    var user = userCredential.user;
    // ...
  })
  .catch((error) => {
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });

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

באותו אופן כמו בשיטות כניסה אחרות (כגון signInWithEmailAndPassword() ו- signInWithCredential() ) אובייקט ה- auth בכללי מסד הנתונים שלך בזמן אמת והאובייקט request.auth בכללי האבטחה שלך בענן אחסון יאוכלס עם ה- uid של המשתמש. במקרה זה, ה- uid יהיה זה שציינת בעת יצירת האסימון המותאם אישית.

כללי מסד נתונים

{
  "rules": {
    "adminContent": {
      ".read": "auth.uid === 'some-uid'"
    }
  }
}

כללי אחסון

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /adminContent/{filename} {
      allow read, write: if request.auth != null && request.auth.uid == "some-uid";
    }
  }
}

אם האסימון המותאם אישית מכיל תביעות נוספות, ניתן להפנות אותן auth.token (Firebase Realtime Database) או ל- request.auth.token (אחסון ענן) בכללים שלך:

כללי מסד נתונים

{
  "rules": {
    "premiumContent": {
      ".read": "auth.token.premiumAccount === true"
    }
  }
}

כללי אחסון

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /premiumContent/{filename} {
      allow read, write: if request.auth.token.premiumAccount == true;
    }
  }
}

צור אסימונים מותאמים אישית באמצעות ספריית JWT של צד שלישי

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

תביעות אסימון בהתאמה אישית
alg אַלגוֹרִיתְם "RS256"
iss מנפיק כתובת הדואר האלקטרוני של חשבון השירות שלך
sub נושא כתובת הדואר האלקטרוני של חשבון השירות שלך
aud קהל "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat הונפק בזמן הזמן הנוכחי, בשניות מאז תקופת יוניקס
exp תאריך תפוגה הזמן, בשניות מאז עידן UNIX, בו האסימון פג. זה יכול להיות מקסימום 3600 שניות מאוחר יותר מה- iat .
הערה: זה שולט רק בזמן בו האסימון המותאם אישית עצמו פג. אך ברגע signInWithCustomToken() משתמש באמצעות signInWithCustomToken() , הם יישארו signInWithCustomToken() למכשיר עד שההפעלה שלהם תבטל או יציאת המשתמש.
uid המזהה הייחודי של המשתמש המחובר חייב להיות מחרוזת באורך של 1-36 תווים
claims (אופציונלי) תביעות מותאמות אישית אופציונליות לכלול במשתני auth / request.auth לכללי האבטחה

להלן כמה יישומים לדוגמה כיצד ליצור אסימונים מותאמים אישית במגוון שפות ש- SDK Admin של Firebase אינו תומך בהן:

PHP

שימוש ב- php-jwt :

// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;

// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";

function create_custom_token($uid, $is_premium_account) {
  global $service_account_email, $private_key;

  $now_seconds = time();
  $payload = array(
    "iss" => $service_account_email,
    "sub" => $service_account_email,
    "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
    "iat" => $now_seconds,
    "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
    "uid" => $uid,
    "claims" => array(
      "premium_account" => $is_premium_account
    )
  );
  return JWT::encode($payload, $private_key, "RS256");
}

אוֹדֶם

באמצעות ruby-jwt :

require "jwt"

# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

def create_custom_token(uid, is_premium_account)
  now_seconds = Time.now.to_i
  payload = {:iss => $service_account_email,
             :sub => $service_account_email,
             :aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :uid => uid,
             :claims => {:premium_account => is_premium_account}}
  JWT.encode payload, $private_key, "RS256"
end

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

פתרון תקלות

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

ממשק ה- API של IAM אינו מופעל

אם אתה מציין מזהה חשבון שירות לחתימת אסימונים אתה עלול לקבל שגיאה דומה לזו הבאה:

Identity and Access Management (IAM) API has not been used in project
1234567890 before or it is disabled. Enable it by visiting
https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890
then retry. If you enabled this API recently, wait a few minutes for the action
to propagate to our systems and retry.

ה- Firkase Admin SDK משתמש ב- IAM API לחתימת אסימונים. שגיאה זו מצביעה על כך ש- IAM API אינו מופעל כעת עבור פרויקט Firebase שלך. פתח את הקישור בהודעת השגיאה בדפדפן אינטרנט ולחץ על כפתור "אפשר API" כדי לאפשר אותו לפרויקט שלך.

לחשבון שירות אין הרשאות נדרשות

אם חשבון השירות ש- SDK מנהל המערכת של Firebase פועל iam.serviceAccounts.signBlob הרשאת iam.serviceAccounts.signBlob , ייתכן שתקבל הודעת שגיאה כמו הבאה:

Permission iam.serviceAccounts.signBlob is required to perform this operation
on service account projects/-/serviceAccounts/{your-service-account-id}.

הדרך הקלה ביותר לפתור זאת היא להעניק את תפקיד ה- IAM "יוצר חשבון אסימון חשבון" לחשבון השירות המדובר, בדרך כלל {project-name}@appspot.gserviceaccount.com :

  1. פתח את דף ה- IAM והניהול במסוף הענן של Google.
  2. בחר בפרויקט שלך ולחץ על "המשך".
  3. לחץ על סמל העריכה המתאים לחשבון השירות שברצונך לעדכן.
  4. לחץ על "הוסף עוד תפקיד".
  5. הקלידו "יוצר אסימון חשבון שירות" במסנן החיפוש ובחרו אותו מתוך התוצאות.
  6. לחץ על "שמור" כדי לאשר את הענקת התפקיד.

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

קביעת חשבון השירות נכשלה

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

Failed to determine service account ID. Initialize the SDK with service account
credentials or specify a service account ID with iam.serviceAccounts.signBlob
permission.

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