تمنحك Firebase إمكانية التحكّم الكامل في المصادقة من خلال السماح لك بمصادقة المستخدمين أو الأجهزة باستخدام رموز JSON المميّزة للويب (JWT) الآمنة. يمكنك إنشاء هذه الرموز المميزة على الخادم الخاص بك، وإعادة إرسالها إلى جهاز العميل، ثم استخدامها للمصادقة من خلال طريقة signInWithCustomToken()
.
لتحقيق ذلك، يجب إنشاء نقطة نهاية للخادم تقبل بيانات اعتماد تسجيل الدخول، مثل اسم المستخدم وكلمة المرور، وإذا كانت بيانات الاعتماد صالحة، يتم عرض رمز JWT مخصّص. يمكن بعد ذلك استخدام رمز JWT المخصّص الذي يعرضه الخادم في جهاز العميل للمصادقة باستخدام Firebase (iOS+ وAndroid والويب). بعد المصادقة، سيتم استخدام هذه الهوية عند الوصول إلى خدمات Firebase الأخرى، مثل Firebase Realtime Database وCloud Storage. بالإضافة إلى ذلك، ستتوفّر محتويات رمز JWT في العنصر auth
ضمن Realtime Database Security Rules والعنصر request.auth
ضمن Cloud Storage Security Rules.
يمكنك إنشاء رمز مميّز مخصّص باستخدام حزمة تطوير البرامج (SDK) للمشرف في Firebase، أو يمكنك استخدام مكتبة JWT تابعة لجهة خارجية إذا كان الخادم مكتوبًا بلغة لا تتوافق مع Firebase بشكلٍ أصلي.
قبل البدء
الرموز المميزة المخصّصة هي رموز JWT موقَّعة، حيث ينتمي المفتاح الخاص المستخدَم في التوقيع إلى حساب خدمة Google. هناك عدة طرق لتحديد حساب خدمة Google الذي يجب أن تستخدمه حزمة Firebase Admin SDK لتوقيع الرموز المميزة المخصّصة:
- استخدام ملف JSON لحساب الخدمة: يمكن استخدام هذه الطريقة في أي بيئة، ولكنها تتطلّب منك تضمين ملف JSON لحساب الخدمة مع الرمز البرمجي. يجب توخّي الحذر الشديد لضمان عدم إفشاء ملف JSON الخاص بحساب الخدمة لأطراف خارجية.
- السماح لحزمة SDK للمشرف باكتشاف حساب خدمة -- يمكن استخدام هذه الطريقة في البيئات التي تديرها Google، مثل "وظائف السحابة الإلكترونية من Google" وApp Engine. قد تحتاج إلى ضبط بعض الأذونات الإضافية من خلال وحدة تحكّم Google Cloud.
- استخدام معرّف حساب خدمة: عند استخدام هذه الطريقة في بيئة تديرها Google، سيتم توقيع الرموز المميزة باستخدام مفتاح حساب الخدمة المحدّد. ومع ذلك، تستخدم هذه الخدمة خدمة ويب بعيدة، وقد تحتاج إلى ضبط أذونات إضافية لحساب الخدمة هذا من خلال وحدة تحكّم Google Cloud.
استخدام ملف JSON لحساب الخدمة
تحتوي ملفات JSON الخاصة بحسابات الخدمة على جميع المعلومات المتعلقة بحسابات الخدمة (بما في ذلك المفتاح الخاص RSA). ويمكن تنزيلها من وحدة تحكّم Firebase. اتّبِع تعليمات إعداد حزمة SDK للمشرف للحصول على مزيد من المعلومات حول كيفية تهيئة حزمة SDK للمشرف باستخدام ملف JSON لحساب الخدمة.
تُعدّ طريقة التهيئة هذه مناسبة لمجموعة كبيرة من عمليات نشر حزمة SDK للمشرف. كما تتيح حزمة تطوير البرامج (SDK) للمشرف إنشاء رموز مميّزة مخصّصة وتوقيعها محليًا، بدون إجراء أي طلبات من واجهة برمجة التطبيقات عن بُعد. العيب الرئيسي في هذا الأسلوب هو أنّه يتطلّب منك تضمين ملف JSON لحساب الخدمة مع الرمز البرمجي. يُرجى أيضًا العِلم أنّ المفتاح الخاص في ملف JSON لحساب الخدمة هو معلومات حساسة، ويجب اتّخاذ احتياطات خاصة للحفاظ على سريته. على وجه التحديد، تجنَّب إضافة ملفات JSON لحسابات الخدمة إلى أنظمة التحكم بالإصدارات العامة.
السماح لحزمة تطوير البرامج (SDK) للمشرف باكتشاف حساب خدمة
إذا تم نشر الرمز في بيئة تديرها Google، يمكن أن تحاول حزمة SDK للمشرف العثور تلقائيًا على وسيلة لتوقيع الرموز المميزة المخصّصة:
إذا تم نشر الرمز البرمجي في بيئة App Engine عادية للغة Java أو Python أو Go، يمكن أن تستخدم حزمة SDK للمشرف خدمة "هوية التطبيق" المتوفّرة في تلك البيئة لتوقيع الرموز المميزة المخصّصة. توقّع خدمة "هوية التطبيق" البيانات باستخدام حساب خدمة توفّره Google App Engine لتطبيقك.
إذا تم نشر الرمز في بيئة مُدارة أخرى (مثل Google Cloud Functions أو Google Compute Engine)، يمكن أن تكتشف حزمة تطوير البرامج (SDK) الخاصة بمشرفي Firebase تلقائيًا سلسلة معرّف حساب الخدمة من خادم البيانات الوصفية المحلي. يتم بعد ذلك استخدام معرّف حساب الخدمة الذي تم اكتشافه مع خدمة IAM لتوقيع الرموز المميزة عن بُعد.
للاستفادة من طرق التوقيع هذه، عليك تهيئة حزمة تطوير البرامج (SDK) باستخدام بيانات الاعتماد التلقائية للتطبيق من Google وعدم تحديد سلسلة معرّف حساب الخدمة:
Node.js
initializeApp();
Java
FirebaseApp.initializeApp();
Python
default_app = firebase_admin.initialize_app()
Go
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) في وحدة تحكّم Google Cloud لمنح حسابات الخدمة التلقائية الأذونات اللازمة. يُرجى الاطّلاع على قسم "تحديد المشاكل وحلّها" أدناه لمعرفة المزيد من التفاصيل.
استخدام رقم تعريف حساب خدمة
للحفاظ على الاتساق بين الأجزاء المختلفة من تطبيقك، يمكنك تحديد رقم تعريف حساب خدمة سيتم استخدام مفاتيحه لتوقيع الرموز المميزة عند التشغيل في بيئة تديرها Google. يمكن أن يؤدي ذلك إلى تبسيط سياسات إدارة الهوية وإمكانية الوصول (IAM) وزيادة أمانها، وتجنُّب الحاجة إلى تضمين ملف JSON لحساب الخدمة في الرمز البرمجي.
يمكن العثور على معرّف حساب الخدمة في
Google Cloud console،
أو في حقل 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);
Python
options = {
'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)
Go
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",
});
إنّ أرقام تعريف حسابات الخدمة ليست معلومات حساسة، وبالتالي فإنّ الكشف عنها ليس له أي تأثير. ومع ذلك، لتوقيع الرموز المميزة المخصّصة باستخدام حساب الخدمة المحدّد، يجب أن تستدعي حزمة Firebase Admin SDK خدمة بعيدة.
بالإضافة إلى ذلك، يجب التأكّد من أنّ حساب الخدمة الذي يستخدمه Admin SDK لإجراء هذا الطلب، وهو عادةً {project-name}@appspot.gserviceaccount.com
، لديه iam.serviceAccounts.signBlob
الإذن.
يُرجى الاطّلاع على قسم "تحديد المشاكل وحلّها" أدناه لمعرفة المزيد من التفاصيل.
إنشاء رموز مميّزة مخصّصة باستخدام حزمة تطوير البرامج (SDK) للمشرف في Firebase
تتضمّن حزمة تطوير البرامج (SDK) للمشرف في Firebase طريقة مدمجة لإنشاء رموز مميّزة مخصّصة. يجب توفير 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
Python
uid = 'some-uid'
custom_token = auth.create_custom_token(uid)
Go
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
Python
uid = 'some-uid'
additional_claims = {
'premiumAccount': True
}
custom_token = auth.create_custom_token(uid, additional_claims)
Go
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) {
// ...
}];
Swift
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
// ...
}
Android
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);
}
}
});
Unity
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.AuthResult result = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
result.User.DisplayName, result.User.UserId);
});
C++
firebase::Future<firebase::auth::AuthResult> result =
auth->SignInWithCustomToken(custom_token);
Web
firebase.auth().signInWithCustomToken(token)
.then((userCredential) => {
// Signed in
var user = userCredential.user;
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Web
import { getAuth, signInWithCustomToken } from "firebase/auth";
const auth = getAuth();
signInWithCustomToken(auth, token)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
في حال نجاح عملية المصادقة، سيتم تسجيل دخول المستخدم إلى تطبيق العميل باستخدام الحساب المحدّد بواسطة uid
المضمّن في الرمز المميّز المخصّص. إذا لم يكن هذا الحساب متوفّرًا من قبل، سيتم إنشاء سجلّ لهذا المستخدم.
بالطريقة نفسها التي تتّبعها طرق تسجيل الدخول الأخرى (مثل
signInWithEmailAndPassword()
وsignInWithCredential()
)، سيتم ملء العنصر auth
في Realtime Database Security Rules
والعنصر request.auth
في
Cloud Storage Security Rules
بـ 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
(Cloud Storage) في القواعد:
قواعد البيانات
{
"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 تابعة لجهة خارجية
إذا كانت لغة الخلفية لا تتضمّن حزمة تطوير برامج (SDK) رسمية خاصة بـ Firebase Admin، سيظل بإمكانك إنشاء رموز مميّزة مخصّصة يدويًا. أولاً، ابحث عن مكتبة 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 و128 حرفًا، بما في ذلك الحدّين. تحقّق uid الأقصر أداءً أفضل.
|
|
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
استخدام 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
إذا كنت تحدّد معرّف حساب خدمة لتوقيع الرموز المميزة، قد يظهر لك خطأ مشابه لما يلي:
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) للمشرف في Firebase واجهة برمجة التطبيقات IAM API لتوقيع الرموز المميزة. يشير هذا الخطأ إلى أنّ واجهة برمجة التطبيقات IAM غير مفعّلة حاليًا لمشروعك على Firebase. افتح الرابط في رسالة الخطأ في متصفّح ويب، وانقر على الزر "تفعيل واجهة برمجة التطبيقات" لتفعيلها في مشروعك.
لا يملك حساب الخدمة الأذونات المطلوبة
إذا لم يكن حساب الخدمة الذي يتم تشغيل حزمة تطوير البرامج (SDK) الخاصة بمشرف Firebase عليه يملك إذن
iam.serviceAccounts.signBlob
، قد تظهر لك رسالة خطأ مشابهة لما يلي:
Permission iam.serviceAccounts.signBlob is required to perform this operation on service account projects/-/serviceAccounts/{your-service-account-id}.
أسهل طريقة لحلّ هذه المشكلة هي منح حساب الخدمة المعنيّ دور "منشئ الرموز المميزة لحساب الخدمة" في "إدارة الهوية وإمكانية الوصول"، ويكون ذلك عادةً من خلال
{project-name}@appspot.gserviceaccount.com
:
- افتح صفحة إدارة الهوية وإمكانية الوصول في وحدة تحكّم Google Cloud.
- اختَر مشروعك وانقر على "متابعة".
- انقر على رمز التعديل بجانب حساب الخدمة الذي تريد تعديله.
- انقر على "إضافة دور آخر".
- اكتب "Service Account Token Creator" في فلتر البحث، ثم اختَر النتيجة.
- انقر على "حفظ" لتأكيد منح الدور.
يمكنك الرجوع إلى مستندات إدارة الهوية وإمكانية الوصول للحصول على مزيد من التفاصيل حول هذه العملية، أو التعرّف على كيفية تعديل الأدوار باستخدام أدوات سطر الأوامر 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.