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

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

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

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

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

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

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

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

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

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

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

צור אסימונים מותאמים אישית באמצעות ה- SDK לניהול Firebase

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

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

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

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 כדי אסימוני סימן. שגיאה זו מצביעה על כך ש- 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.