تمنحك منصة 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 الذي يجب أن يستخدمه مدير SDK في Firebase لتوقيع الرموز المميّزة المخصّصة:
- استخدام ملف JSON لحساب الخدمة: يمكن استخدام هذه الطريقة في أي بيئة، ولكنها تتطلب منك تجميع ملف JSON لحساب الخدمة مع الرمز البرمجي. يجب توخي الحذر الشديد لضمان عدم الكشف عن ملف JSON الخاص بحساب الخدمة لأطراف خارجية.
- السماح لـ Admin SDK بالعثور على حساب خدمة -- يمكن استخدام هذه الطريقة في البيئات التي تديرها Google، مثل Google Cloud Functions وApp Engine. قد تحتاج إلى ضبط بعض الأذونات الإضافية من خلال وحدة تحكّم Google Cloud.
- استخدام رقم تعريف حساب الخدمة: عند استخدام هذه الطريقة في بيئة تديرها Google، سيتم توقيع الرموز المميّزة باستخدام مفتاح حساب الخدمة المحدّد. ومع ذلك، تستخدم هذه الأداة خدمة ويب عن بُعد، وقد تحتاج إلى ضبط أذونات إضافية لحساب الخدمة هذا من خلال وحدة تحكّم Google Cloud.
استخدام ملف JSON لحساب الخدمة
تحتوي ملفات JSON لحسابات الخدمة على جميع المعلومات المتعلقة بحسابات الخدمة (بما في ذلك مفتاح RSA الخاص). ويمكن تنزيلها من وحدة تحكّم Firebase. اتّبِع تعليمات إعداد مدير SDK للحصول على مزيد من المعلومات حول كيفية إعداد مدير SDK باستخدام ملف JSON لحساب الخدمة.
هذه الطريقة مناسبة لمجموعة كبيرة من عمليات نشر حزمة SDK للمشرف. كما تتيح لـ Admin 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()
متابعة
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 لكي تعمل عملية إنشاء الرمز المميّز المخصّص. قد تحتاج إلى استخدام قسم إدارة الهوية وإمكانية الوصول والمشرف في وحدة تحكّم Google Cloud لمنح حسابات الخدمة التلقائية الأذونات اللازمة. لمزيد من التفاصيل، يُرجى الاطّلاع على قسم تحديد المشاكل وحلّها أدناه.
استخدام رقم تعريف حساب الخدمة
للحفاظ على الاتساق بين الأجزاء المختلفة من تطبيقك، يمكنك تحديد رقم تعريف حساب الخدمة الذي سيتم استخدام مفاتيحه لتوقيع الرموز المميزة عند التشغيل في بيئة تديرها Google. يمكن أن يجعل ذلك سياسات "إدارة الهوية وإمكانية الوصول" أبسط وأكثر أمانًا، ويجنّبك الحاجة إلى تضمين ملف JSON لحساب الخدمة في الرمز البرمجي.
يمكن العثور على رقم تعريف حساب الخدمة في
وحدة تحكّم Google Cloud،
أو في حقل 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)
متابعة
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.
لمزيد من التفاصيل، يُرجى الاطّلاع على قسم تحديد المشاكل وحلّها أدناه.
إنشاء رموز مميّزة مخصّصة باستخدام مدير 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)
متابعة
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)
متابعة
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، سيظل بإمكانك إنشاء رموز مميّزة مخصّصة يدويًا. أولاً، ابحث عن مكتبة JWT تابعة لجهة خارجية للغتك. بعد ذلك، استخدِم مكتبة JWT هذه لإنشاء رمز JWT يتضمّن المطالبات التالية:
| مطالبات الرموز المميّزة المخصّصة | ||
|---|---|---|
alg |
خوارزمية | "RS256" |
iss |
جهة الإصدار | عنوان البريد الإلكتروني لحساب الخدمة الخاص بمشروعك |
sub |
الموضوع | عنوان البريد الإلكتروني لحساب الخدمة الخاص بمشروعك |
aud |
الجمهور | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
وقت الإصدار | الوقت الحالي بالثواني منذ بدء حقبة يونكس |
exp |
وقت انتهاء الصلاحية |
الوقت بالثواني منذ بداية حقبة يونكس، والذي تنتهي فيه صلاحية الرمز المميّز. ويمكن أن يكون بعد 3600 ثانية كحدّ أقصى من iat.
ملاحظة: يتحكّم هذا الإعداد فقط في وقت انتهاء صلاحية الرمز المخصّص نفسه. ولكن بعد تسجيل دخول المستخدم باستخدام signInWithCustomToken()، سيظل مسجِّلاً الدخول إلى
الجهاز إلى أن يتم إبطال جلسته أو يسجّل المستخدم الخروج.
|
uid |
يجب أن يكون المعرّف الفريد للمستخدم الذي سجّل الدخول عبارة عن سلسلة تتراوح بين حرف واحد و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. يمكنك الاطّلاع على عيّنات التعليمات البرمجية أعلاه لمعرفة كيفية إجراء ذلك.
تحديد المشاكل وحلّها
يستعرض هذا القسم بعض المشاكل الشائعة التي قد يواجهها المطوّرون عند إنشاء رموز مميّزة مخصّصة، وكيفية حلّها.
واجهة برمجة التطبيقات لإدارة الهوية وإمكانية الوصول غير مفعَّلة
إذا كنت تحدّد رقم تعريف حساب خدمة لتوقيع الرموز المميّزة، قد يظهر لك خطأ مشابه لما يلي:
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 واجهة برمجة تطبيقات إدارة الهوية وإمكانية الوصول لتوقيع الرموز المميّزة. يشير هذا الخطأ إلى أنّ واجهة برمجة التطبيقات لإدارة الهوية وإمكانية الوصول غير مفعَّلة حاليًا لمشروع 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}.
لحلّ هذه المشكلة، عليك منح دور منشئ الرمز المميّز لحساب الخدمة ضمن "إدارة الهوية وإمكانية الوصول" إلى حساب الخدمة المناسب. يعتمد حساب الخدمة التلقائي المستخدَم على البيئة وإصدار Cloud Functions:
- Cloud Functions (الجيل الأول): تستخدم حساب خدمة App Engine التلقائي.
- Cloud Functions (الجيل الثاني): تستخدم حساب خدمة Compute Engine التلقائي.
في وحدة تحكّم 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).