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

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 לחתימה על אסימונים מותאמים אישית:

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

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

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

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

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

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

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

  • אם הקוד שלך נפרס בכמה בסביבה מנוהלת אחרת (פונקציות כגון Google Cloud,: Google Compute 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:

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

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

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

זיהוי חשבון השירות ניתן למצוא את מסוף ענן גוגל , או 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 של מנהל המערכת משתמש כדי לבצע שיחה זו -usually {project-name}@appspot.gserviceaccount.com - יש 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 (Database Firebase זמן אמת) או 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() , הם יישארו מחוברים למכשיר עד הפגישה שלהם תבוטל או המשתמש מתנתק.
uid המזהה הייחודי של המשתמש המחובר חייב להיות מחרוזת באורך של 1-36 תווים
claims (אופציונלי) טענות מנהג אופציונאלי לכלול בכללי אבטחת auth / request.auth משתנה

להלן כמה מימושים לדוגמא כיצד ליצור אסימונים מותאמים אישית במגוון שפות ש- SDK מנהל המערכת של 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.

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

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

אם שירות חשבון SDK של מנהל מערכת Firebase פועל כמו אין 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 Cloud Console.
  2. בחר בפרויקט שלך ולחץ על "המשך".
  3. לחץ על סמל העריכה המתאים לחשבון השירות שברצונך לעדכן.
  4. לחץ על "הוסף עוד תפקיד".
  5. הקלד "יוצר אסימון חשבון שירות" במסנן החיפוש, ובחר אותו מבין התוצאות.
  6. לחץ על "שמור" כדי לאשר את הענקת התפקיד.

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

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

אם מתקבלת הודעת שגיאה הדומה להודעה הבאה, ה- SDK למנהל המערכת של Firebase לא אותחל כהלכה.

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.