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

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

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

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

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

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

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

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

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

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

מתן אפשרות ל-Admin SDK לגלות חשבון שירות

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

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

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

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

Node.js

initializeApp();

Java

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 Admin חייב לגלות מחרוזת מזהה חשבון שירות, הוא עושה זאת כאשר הקוד שלך יוצר אסימון מותאם אישית בפעם הראשונה. התוצאה נשמרת במטמון ועושה שימוש חוזר עבור פעולות חתימת אסימון עוקבות. מזהה חשבון השירות שהתגלה אוטומטית הוא בדרך כלל אחד מחשבונות השירות המוגדרים כברירת מחדל שמסופקים על ידי 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

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

Java

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 Admin חייב להפעיל שירות מרוחק. יתר על כן, אתה חייב גם לוודא ששירות חשבון SDK של מנהל מערכת משתמש כדי לבצע שיחה זו -usually {project-name}@appspot.gserviceaccount.com - יש iam.serviceAccounts.signBlob הרשות . עיין בסעיף פתרון הבעיות למטה לפרטים נוספים.

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

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

Node.js

const uid = 'some-uid';

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

Java

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,
};

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

Java

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+

Objective-C
[[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 של צד שלישי

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

תביעות אסימון מותאמות אישית
alg אַלגוֹרִיתְם "RS256"
iss מנפיק כתובת הדוא"ל של חשבון השירות של הפרויקט שלך
sub נושא כתובת הדוא"ל של חשבון השירות של הפרויקט שלך
aud קהל "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat הונפק-בזמן הזמן הנוכחי, בשניות מאז תקופת UNIX
exp תאריך תפוגה הזמן, בשניות מאז עידן UNIX, שבו יפוג האסימון. זה יכול להיות מקסימום של 3600 שניות יאוחר iat .
הערה: זו שולטת רק בתקופה שבה מנהג האסימון עצמו פג. אבל ברגע שאתה לחתום על משתמש באמצעות 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. עיין בדוגמאות הקוד למעלה כיצד לעשות זאת.

פתרון תקלות

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

IAM API לא מופעל

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

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 כדי אסימוני סימן. שגיאה זו מציינת שה-API של IAM אינו מופעל כעת עבור פרויקט 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 Admin לא אותחל כהלכה.

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.