Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

توکن های سفارشی ایجاد کنید

با مجموعه‌ها، منظم بمانید ذخیره و دسته‌بندی محتوا براساس اولویت‌های شما.

Firebase با اجازه دادن به شما برای احراز هویت کاربران یا دستگاه‌ها با استفاده از JSON Web Tokens (JWT) کنترل کاملی بر احراز هویت به شما می‌دهد. شما این نشانه‌ها را روی سرور خود تولید می‌کنید، آنها را به یک دستگاه مشتری برمی‌گردانید، و سپس از آنها برای احراز هویت از طریق signInWithCustomToken() استفاده می‌کنید.

برای دستیابی به این هدف، باید یک نقطه پایانی سرور ایجاد کنید که اعتبار ورود به سیستم را بپذیرد - مانند نام کاربری و رمز عبور - و اگر اعتبارنامه معتبر باشد، یک JWT سفارشی برمی‌گرداند. سپس JWT سفارشی که از سرور شما بازگردانده می‌شود، می‌تواند توسط دستگاه مشتری برای احراز هویت با Firebase ( iOS+ ، Android ، وب ) استفاده شود. پس از احراز هویت، این هویت هنگام دسترسی به سایر خدمات Firebase، مانند پایگاه داده بیدرنگ Firebase و Cloud Storage استفاده می‌شود. علاوه بر این، محتوای JWT در شی auth در قوانین پایگاه داده بیدرنگ شما و شی request.auth در قوانین امنیت فضای ذخیره سازی ابری شما در دسترس خواهد بود.

می‌توانید با Firebase Admin SDK یک توکن سفارشی ایجاد کنید، یا اگر سرور شما به زبانی نوشته شده است که Firebase به طور بومی پشتیبانی نمی‌کند، می‌توانید از کتابخانه JWT شخص ثالث استفاده کنید.

قبل از اینکه شروع کنی

توکن‌های سفارشی JWT‌های امضا شده‌ای هستند که کلید خصوصی مورد استفاده برای امضا به حساب سرویس Google تعلق دارد. راه‌های مختلفی برای تعیین حساب سرویس Google که باید توسط Firebase Admin SDK برای امضای توکن‌های سفارشی استفاده شود، وجود دارد:

  • استفاده از فایل JSON حساب سرویس -- این روش را می توان در هر محیطی استفاده کرد، اما از شما می خواهد که فایل JSON حساب سرویس را همراه با کد خود بسته بندی کنید. باید مراقب باشید تا اطمینان حاصل شود که فایل JSON حساب سرویس در معرض اشخاص خارجی قرار نمی گیرد.
  • اجازه دادن به Admin SDK برای کشف یک حساب سرویس -- این روش را می توان در محیط های مدیریت شده توسط Google مانند Google Cloud Functions و App Engine استفاده کرد. ممکن است مجبور شوید برخی از مجوزهای اضافی را از طریق Google Cloud Console پیکربندی کنید.
  • استفاده از شناسه حساب سرویس -- هنگامی که در یک محیط مدیریت شده توسط Google استفاده می شود، این روش با استفاده از کلید حساب سرویس مشخص شده، نشانه ها را امضا می کند. با این حال، از یک سرویس وب راه دور استفاده می کند، و ممکن است مجبور شوید مجوزهای اضافی را برای این حساب سرویس از طریق Google Cloud Console پیکربندی کنید.

استفاده از فایل JSON حساب سرویس

فایل‌های JSON حساب سرویس حاوی تمام اطلاعات مربوط به حساب‌های سرویس (از جمله کلید خصوصی RSA) هستند. آنها را می توان از کنسول Firebase دانلود کرد. دستورالعمل‌های راه‌اندازی Admin SDK را برای اطلاعات بیشتر در مورد نحوه راه‌اندازی اولیه SDK مدیریت با یک فایل JSON حساب سرویس دنبال کنید.

این روش مقداردهی اولیه برای طیف وسیعی از استقرار Admin SDK مناسب است. همچنین Admin SDK را قادر می‌سازد تا توکن‌های سفارشی را به صورت محلی ایجاد و امضا کند، بدون اینکه تماس API از راه دور برقرار کند. اشکال اصلی این روش این است که شما را ملزم می کند یک فایل JSON حساب سرویس را به همراه کد خود بسته بندی کنید. همچنین توجه داشته باشید که کلید خصوصی در فایل JSON حساب سرویس، اطلاعات حساسی است و باید برای محرمانه نگه داشتن آن دقت ویژه ای کرد. به طور خاص، از افزودن فایل‌های JSON حساب سرویس به کنترل نسخه عمومی خودداری کنید.

اجازه دادن به Admin SDK یک حساب سرویس را کشف کند

اگر کد شما در محیطی که توسط Google مدیریت می‌شود مستقر شده است، Admin SDK می‌تواند به طور خودکار ابزاری را برای امضای نشانه‌های سفارشی کشف کند:

  • اگر کد شما در محیط استاندارد App Engine برای Java، Python یا Go مستقر شده است، Admin SDK می تواند از سرویس App Identity موجود در آن محیط برای امضای توکن های سفارشی استفاده کند. سرویس App Identity داده ها را با استفاده از حساب سرویسی که توسط Google App Engine برای برنامه شما ارائه شده است امضا می کند.

  • اگر کد شما در محیط مدیریت شده دیگری (مثلاً Google Cloud Functions، Google Compute Engine) مستقر شده باشد، Firebase Admin SDK می تواند به طور خودکار یک رشته شناسه حساب سرویس را از سرور ابرداده محلی پیدا کند. سپس شناسه حساب سرویس کشف شده همراه با سرویس IAM برای امضای توکن ها از راه دور استفاده می شود.

برای استفاده از این روش‌های امضا، SDK را با اطلاعات کاربری پیش‌فرض Google Application مقداردهی اولیه کنید و رشته ID حساب سرویس را مشخص نکنید:

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 باید رشته ID حساب سرویس را پیدا کند، زمانی که کد شما برای اولین بار یک توکن سفارشی ایجاد می‌کند، این کار را انجام می‌دهد. نتیجه در حافظه پنهان ذخیره می شود و برای عملیات امضای رمز بعدی مجددا استفاده می شود. شناسه حساب سرویس کشف شده خودکار معمولاً یکی از حساب‌های خدمات پیش‌فرض ارائه شده توسط Google Cloud است:

درست مانند شناسه‌های حساب سرویس که به‌صراحت مشخص شده‌اند، شناسه‌های حساب سرویس با کشف خودکار باید مجوز iam.serviceAccounts.signBlob را داشته باشند تا ایجاد توکن سفارشی کار کند. برای اعطای مجوزهای لازم به حساب‌های سرویس پیش‌فرض، ممکن است مجبور شوید از IAM و بخش مدیریت Google Cloud Console استفاده کنید. برای جزئیات بیشتر به بخش عیب یابی زیر مراجعه کنید.

با استفاده از شناسه حساب سرویس

برای حفظ یکپارچگی بین بخش‌های مختلف برنامه‌تان، می‌توانید شناسه حساب خدماتی را مشخص کنید که کلیدهای آن برای امضای نشانه‌ها هنگام اجرا در یک محیط تحت مدیریت 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',
});

جاوا

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 باید یک سرویس راه دور را فراخوانی کند. علاوه بر این، باید مطمئن شوید که حساب سرویس Admin 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+

هدف-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);

Web version 8

firebase.auth().signInWithCustomToken(token)
  .then((userCredential) => {
    // Signed in
    var user = userCredential.user;
    // ...
  })
  .catch((error) => {
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });

Web version 9

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 در قوانین پایگاه داده بیدرنگ و شی request.auth در قوانین امنیتی Cloud Storage شما با 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 شخص ثالث، توکن های سفارشی ایجاد کنید

اگر باطن شما به زبانی است که Firebase Admin SDK رسمی ندارد، همچنان می توانید به صورت دستی توکن های سفارشی ایجاد کنید. ابتدا یک کتابخانه JWT شخص ثالث برای زبان خود پیدا کنید. سپس، از آن کتابخانه JWT برای ایجاد یک JWT که شامل ادعاهای زیر است استفاده کنید:

ادعاهای توکن سفارشی
alg الگوریتم "RS256"
iss صادر کننده آدرس ایمیل حساب خدمات پروژه شما
sub موضوع آدرس ایمیل حساب خدمات پروژه شما
aud حضار "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat صادر شده در زمان زمان کنونی، در ثانیه از دوران یونیکس
exp زمان انقضا زمان، در ثانیه از دوره یونیکس، که در آن توکن منقضی می‌شود. می تواند حداکثر 3600 ثانیه دیرتر از iat باشد.
توجه: این فقط زمانی را کنترل می کند که خود توکن سفارشی منقضی شود. اما هنگامی که کاربر را با استفاده از signInWithCustomToken() وارد سیستم کردید، تا زمانی که جلسه آنها باطل شود یا کاربر از سیستم خارج نشود، وارد دستگاه می‌شوند.
uid شناسه منحصربه‌فرد کاربری که وارد سیستم شده است باید یک رشته با طول بین 1 تا 36 کاراکتر باشد.
claims (اختیاری) ادعاهای سفارشی اختیاری برای گنجاندن متغیرهای auth / request.auth در قوانین امنیتی

در اینجا چند نمونه پیاده سازی از نحوه ایجاد توکن های سفارشی در زبان های مختلف که Firebase Admin SDK پشتیبانی نمی کند آورده شده است:

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.

Firebase Admin SDK از IAM API برای امضای توکن ها استفاده می کند. این خطا نشان می دهد که IAM API در حال حاضر برای پروژه Firebase شما فعال نیست. پیوند موجود در پیام خطا را در یک مرورگر وب باز کنید و روی دکمه "فعال کردن API" کلیک کنید تا آن را برای پروژه خود فعال کنید.

حساب سرویس مجوزهای لازم را ندارد

اگر حساب سرویس Firebase Admin SDK بدون مجوز 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 را در Google Cloud Console باز کنید.
  2. پروژه خود را انتخاب کنید و روی "ادامه" کلیک کنید.
  3. روی نماد ویرایش مربوط به حساب سرویسی که می خواهید به روز کنید کلیک کنید.
  4. روی "افزودن نقش دیگر" کلیک کنید.
  5. "Service Account Token Creator" را در فیلتر جستجو تایپ کنید و آن را از نتایج انتخاب کنید.
  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 مشخص کنید.