Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

قم بإنشاء رموز مخصصة

يمنحك Firebase تحكمًا كاملاً في المصادقة من خلال السماح لك بمصادقة المستخدمين أو الأجهزة باستخدام رموز الويب JSON الآمنة (JWTs). يمكنك توليد هذه الرموز على الخادم الخاص بك، نقلها إلى جهاز العميل، ومن ثم استخدامها لمصادقة عبر signInWithCustomToken() الأسلوب.

لتحقيق ذلك ، يجب عليك إنشاء نقطة نهاية خادم تقبل بيانات اعتماد تسجيل الدخول - مثل اسم المستخدم وكلمة المرور - وإذا كانت بيانات الاعتماد صالحة ، فتقوم بإرجاع JWT مخصص. ويمكن بعد ذلك JWT مخصصة عاد من الخادم الخاص بك أن تستخدم من قبل جهاز العميل لمصادقة مع Firebase ( دائرة الرقابة الداخلية ، الروبوت ، على شبكة الإنترنت ). بمجرد المصادقة ، سيتم استخدام هذه الهوية عند الوصول إلى خدمات 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 Cloud Console.
  • باستخدام معرف حساب خدمة - عندما تستخدم في بيئة مدارة جوجل، هذه الطريقة ستوقع الرموز باستخدام مفتاح الحساب الخدمة المحددة ل. ومع ذلك ، فإنه يستخدم خدمة ويب بعيدة ، وقد تضطر إلى تكوين أذونات إضافية لحساب الخدمة هذا عبر Google Cloud Console.

استخدام ملف JSON لحساب الخدمة

تحتوي ملفات JSON لحساب الخدمة على جميع المعلومات المقابلة لحسابات الخدمة (بما في ذلك المفتاح الخاص RSA). يمكن تنزيلها من وحدة تحكم Firebase. اتبع مجموعة SDK المسؤول عن تعليمات للمزيد من المعلومات حول كيفية تهيئة SDK المسؤول مع ملف JSON حساب الخدمة.

تعد طريقة التهيئة هذه مناسبة لمجموعة كبيرة من عمليات نشر Admin SDK. كما أنه يمكّن Admin SDK من إنشاء الرموز المميزة المخصصة وتوقيعها محليًا ، دون إجراء أي استدعاءات لواجهة برمجة التطبيقات عن بُعد. العيب الرئيسي لهذا الأسلوب هو أنه يتطلب منك حزم ملف JSON لحساب الخدمة مع التعليمات البرمجية الخاصة بك. لاحظ أيضًا أن المفتاح الخاص في ملف JSON لحساب الخدمة هو معلومات حساسة ، ويجب توخي الحذر بشكل خاص للحفاظ على سريتها. على وجه التحديد ، الامتناع عن إضافة ملفات JSON لحساب الخدمة إلى التحكم في الإصدار العام.

السماح لـ Admin SDK باكتشاف حساب الخدمة

إذا تم نشر الرمز الخاص بك في بيئة تديرها Google ، فيمكن أن يحاول Admin SDK الاكتشاف التلقائي لوسيلة لتوقيع الرموز المميزة المخصصة:

  • إذا تم نشر التعليمات البرمجية في بيئة محرك التطبيقات القياسية لجافا، بيثون أو العودة، يمكن للSDK الادارية استخدام خدمة التطبيقات الهوية موجودة في تلك البيئة لتوقيع الرموز المخصصة. تسجّل خدمة App Identity البيانات باستخدام حساب خدمة يتم توفيره لتطبيقك بواسطة Google App Engine.

  • إذا تم نشر التعليمات البرمجية في بعض بيئة أخرى تمكن (على سبيل المثال وظائف في السحاب من Google، وجوجل حساب المحرك)، ويمكن Firebase الادارية SDK لصناعة السيارات في اكتشاف سلسلة ID حساب الخدمة من المحليين الخادم الفوقية . يتم بعد ذلك استخدام معرف حساب الخدمة المكتشف جنبًا إلى جنب مع خدمة IAM لتوقيع الرموز المميزة عن بُعد.

للاستفادة من طرق التوقيع هذه ، قم بتهيئة SDK باستخدام بيانات اعتماد Google Application Default ولا تحدد سلسلة معرّف حساب الخدمة:

Node.js

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)
}

سي #

FirebaseApp.Create();

لاختبار نفس رمز محليا، تحميل ملف JSON حساب خدمة وتعيين GOOGLE_APPLICATION_CREDENTIALS متغير البيئة للإشارة إلى ذلك.

إذا كان على Firebase Admin SDK اكتشاف سلسلة معرف حساب الخدمة ، فإنها تفعل ذلك عندما تنشئ شفرتك رمزًا مميزًا مخصصًا لأول مرة. يتم تخزين النتيجة مؤقتًا وإعادة استخدامها لعمليات توقيع الرمز المميز اللاحقة. عادةً ما يكون معرف حساب الخدمة المكتشف تلقائيًا أحد حسابات الخدمة الافتراضية التي توفرها Google Cloud:

تماما مثل مع معرفات حساب الخدمة المحددة بوضوح، يجب أن يكون معرفات حساب خدمة السيارات المكتشف في iam.serviceAccounts.signBlob إذن لإنشاء مخصصة رمزي إلى العمل. قد تضطر إلى استخدام IAM و admin قسم وحدة التحكم سحابة جوجل لمنح الخدمة الافتراضية حسابات الأذونات الضرورية. راجع قسم استكشاف الأخطاء وإصلاحها أدناه للحصول على مزيد من التفاصيل.

باستخدام معرف حساب الخدمة

للحفاظ على الاتساق بين أجزاء مختلفة من تطبيقك ، يمكنك تحديد معرف حساب الخدمة الذي سيتم استخدام مفاتيحه لتسجيل الرموز المميزة عند التشغيل في بيئة تديرها 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',
});

جافا

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)
}

سي #

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
    ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});

معرفات حساب الخدمة ليست معلومات حساسة وبالتالي فإن تعرضها غير مهم. ومع ذلك ، لتوقيع الرموز المميزة المخصصة باستخدام حساب الخدمة المحدد ، يجب أن يستدعي Firebase Admin SDK خدمة عن بُعد. وعلاوة على ذلك، يجب أيضا التأكد من أن خدمة حساب SDK الادارية تستخدم لإجراء هذه المكالمة غير عادة {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);
  });

جافا

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)

سي #

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

جافا

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)

سي #

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 (قاعدة بيانات 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 لجهة خارجية

إذا كانت الواجهة الخلفية الخاصة بك بلغة لا تحتوي على حزمة 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 المتغيرات

في ما يلي بعض الأمثلة على عمليات التنفيذ لكيفية إنشاء رموز مخصصة في مجموعة متنوعة من اللغات التي لا تدعمها Firebase Admin SDK:

بي أتش بي

باستخدام 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 غير ممكّنة

إذا كنت تحدد معرف حساب خدمة لتوقيع الرموز المميزة ، فقد تحصل على خطأ مشابه لما يلي:

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.

يستخدم Firebase الادارية SDK ل API IAM إلى الرموز علامة. يشير هذا الخطأ إلى أن واجهة برمجة تطبيقات 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}.

أسهل طريقة لحل هذه هي لمنح "حساب رمز الخدمة الخالق" دور IAM لحساب الخدمة في السؤال، عادة {project-name}@appspot.gserviceaccount.com :

  1. فتح IAM و admin صفحة في وحدة التحكم سحابة جوجل.
  2. حدد مشروعك وانقر على "متابعة".
  3. انقر فوق رمز التحرير المقابل لحساب الخدمة الذي ترغب في تحديثه.
  4. انقر فوق "إضافة دور آخر".
  5. اكتب "مُنشئ حساب الخدمة" في فلتر البحث ، وحدده من النتائج.
  6. انقر على "حفظ" لتأكيد منح الدور.

الرجوع إلى الوثائق IAM لمزيد من التفاصيل حول هذه العملية، أو معرفة كيفية القيام بأدوار تحديث باستخدام أدوات سطر الأوامر gcloud.

فشل تحديد حساب الخدمة

إذا تلقيت رسالة خطأ مشابهة لما يلي ، فهذا يعني أنه لم تتم تهيئة Firebase Admin SDK بشكل صحيح.

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.