获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

Buat Token Khusus

Firebase memberi Anda kontrol penuh atas autentikasi dengan memungkinkan Anda mengautentikasi pengguna atau perangkat menggunakan JSON Web Tokens (JWTs) yang aman. Anda membuat token ini di server Anda, meneruskannya kembali ke perangkat klien, lalu menggunakannya untuk mengautentikasi melalui metode signInWithCustomToken() .

Untuk mencapai ini, Anda harus membuat titik akhir server yang menerima kredensial masuk—seperti nama pengguna dan sandi—dan, jika kredensial valid, mengembalikan JWT kustom. JWT khusus yang dikembalikan dari server Anda kemudian dapat digunakan oleh perangkat klien untuk mengautentikasi dengan Firebase ( iOS+ , Android , web ). Setelah diautentikasi, identitas ini akan digunakan saat mengakses layanan Firebase lainnya, seperti Firebase Realtime Database dan Cloud Storage. Selanjutnya, konten JWT akan tersedia di objek auth di Aturan Realtime Database Anda dan objek request.auth di Aturan Keamanan Cloud Storage Anda.

Anda dapat membuat token khusus dengan Firebase Admin SDK, atau Anda dapat menggunakan perpustakaan JWT pihak ketiga jika server Anda ditulis dalam bahasa yang tidak didukung oleh Firebase.

Sebelum kamu memulai

Token khusus adalah JWT yang ditandatangani dengan kunci pribadi yang digunakan untuk penandatanganan milik akun layanan Google. Ada beberapa cara untuk menentukan akun layanan Google yang harus digunakan oleh Firebase Admin SDK untuk menandatangani token khusus:

  • Menggunakan file JSON akun layanan -- Metode ini dapat digunakan di lingkungan apa pun, tetapi mengharuskan Anda untuk mengemas file JSON akun layanan bersama dengan kode Anda. Perhatian khusus harus diberikan untuk memastikan bahwa file JSON akun layanan tidak diekspos ke pihak eksternal.
  • Membiarkan Admin SDK menemukan akun layanan -- Metode ini dapat digunakan di lingkungan yang dikelola oleh Google seperti Google Cloud Functions dan App Engine. Anda mungkin harus mengonfigurasi beberapa izin tambahan melalui Google Cloud Console.
  • Menggunakan ID akun layanan -- Saat digunakan di lingkungan yang dikelola Google, metode ini akan menandatangani token menggunakan kunci akun layanan yang ditentukan. Namun, ia menggunakan layanan web jarak jauh, dan Anda mungkin harus mengonfigurasi izin tambahan untuk akun layanan ini melalui Google Cloud Console.

Menggunakan file JSON akun layanan

File JSON akun layanan berisi semua informasi yang terkait dengan akun layanan (termasuk kunci pribadi RSA). Mereka dapat diunduh dari konsol Firebase. Ikuti petunjuk penyiapan Admin SDK untuk informasi selengkapnya tentang cara menginisialisasi Admin SDK dengan file JSON akun layanan.

Metode inisialisasi ini cocok untuk berbagai penerapan Admin SDK. Juga memungkinkan Admin SDK untuk membuat dan menandatangani token khusus secara lokal, tanpa melakukan panggilan API jarak jauh. Kelemahan utama dari pendekatan ini adalah Anda harus mengemas file JSON akun layanan bersama dengan kode Anda. Perhatikan juga bahwa kunci pribadi dalam file JSON akun layanan adalah informasi sensitif, dan perhatian khusus harus diberikan untuk menjaga kerahasiaannya. Secara khusus, jangan menambahkan file JSON akun layanan ke kontrol versi publik.

Membiarkan Admin SDK menemukan akun layanan

Jika kode Anda diterapkan di lingkungan yang dikelola oleh Google, Admin SDK dapat mencoba menemukan cara untuk menandatangani token khusus secara otomatis:

  • Jika kode Anda diterapkan di lingkungan standar App Engine untuk Java, Python, atau Go, Admin SDK dapat menggunakan layanan App Identity yang ada di lingkungan tersebut untuk menandatangani token khusus. Layanan App Identity menandatangani data menggunakan akun layanan yang disediakan untuk aplikasi Anda oleh Google App Engine.

  • Jika kode Anda diterapkan di beberapa lingkungan terkelola lainnya (mis. Google Cloud Functions, Google Compute Engine), Firebase Admin SDK dapat secara otomatis menemukan string ID akun layanan dari server metadata lokal . ID akun layanan yang ditemukan kemudian digunakan bersama dengan layanan IAM untuk menandatangani token dari jarak jauh.

Untuk menggunakan metode penandatanganan ini, inisialisasi SDK dengan kredensial Google Application Default dan jangan tentukan string ID akun layanan:

Node.js

initializeApp();

Jawa

FirebaseApp.initializeApp();

Python

default_app = firebase_admin.initialize_app()

Pergi

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create();

Untuk menguji kode yang sama secara lokal, unduh file JSON akun layanan dan setel variabel lingkungan GOOGLE_APPLICATION_CREDENTIALS agar mengarah ke sana.

Jika Firebase Admin SDK harus menemukan string ID akun layanan, ia melakukannya saat kode Anda membuat token khusus untuk pertama kalinya. Hasilnya di-cache dan digunakan kembali untuk operasi penandatanganan token berikutnya. ID akun layanan yang ditemukan secara otomatis biasanya merupakan salah satu akun layanan default yang disediakan oleh Google Cloud:

Sama seperti ID akun layanan yang ditentukan secara eksplisit, ID akun layanan yang ditemukan secara otomatis harus memiliki izin iam.serviceAccounts.signBlob agar pembuatan token khusus dapat berfungsi. Anda mungkin harus menggunakan bagian IAM dan admin dari Google Cloud Console untuk memberikan izin yang diperlukan kepada akun layanan default. Lihat bagian pemecahan masalah di bawah untuk detail selengkapnya.

Menggunakan ID akun layanan

Untuk menjaga konsistensi antara berbagai bagian aplikasi, Anda dapat menentukan ID akun layanan yang kuncinya akan digunakan untuk menandatangani token saat berjalan di lingkungan yang dikelola Google. Ini dapat membuat kebijakan IAM lebih sederhana dan lebih aman, serta menghindari keharusan menyertakan file JSON akun layanan dalam kode Anda.

ID akun layanan dapat ditemukan di Google Cloud Console , atau di bidang client_email dari file JSON akun layanan yang diunduh. ID akun layanan adalah alamat email yang memiliki format berikut: <client-id>@<project-id>.iam.gserviceaccount.com . Mereka secara unik mengidentifikasi akun layanan di proyek Firebase dan Google Cloud.

Untuk membuat token khusus menggunakan ID akun layanan terpisah, inisialisasi SDK seperti yang ditunjukkan di bawah ini:

Node.js

initializeApp({
  serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});

Jawa

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)

Pergi

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

ID akun layanan bukanlah informasi sensitif dan oleh karena itu paparannya tidak penting. Namun, untuk menandatangani token khusus dengan akun layanan yang ditentukan, Firebase Admin SDK harus memanggil layanan jarak jauh. Selain itu, Anda juga harus memastikan bahwa akun layanan yang digunakan Admin SDK untuk melakukan panggilan ini —biasanya {project-name}@appspot.gserviceaccount.com — memiliki izin iam.serviceAccounts.signBlob . Lihat bagian pemecahan masalah di bawah untuk detail selengkapnya.

Buat token khusus menggunakan Firebase Admin SDK

Firebase Admin SDK memiliki metode bawaan untuk membuat token khusus. Minimal, Anda perlu memberikan uid , yang dapat berupa string apa pun tetapi harus secara unik mengidentifikasi pengguna atau perangkat yang Anda autentikasi. Token ini kedaluwarsa setelah satu jam.

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

Jawa

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)

Pergi

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

Anda juga dapat secara opsional menentukan klaim tambahan untuk disertakan dalam token khusus. Misalnya, di bawah ini, bidang premiumAccount telah ditambahkan ke token khusus, yang akan tersedia di objek auth / request.auth di Aturan Keamanan Anda:

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

Jawa

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)

Pergi

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

Nama token khusus yang dipesan

Masuk menggunakan token khusus pada klien

Setelah Anda membuat token khusus, Anda harus mengirimkannya ke aplikasi klien Anda. Aplikasi klien mengautentikasi dengan token khusus dengan memanggil signInWithCustomToken() :

iOS+

Objective-C
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
Cepat
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);
                }
            }
        });

Persatuan

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

Jika otentikasi berhasil, pengguna Anda sekarang akan masuk ke aplikasi klien Anda dengan akun yang ditentukan oleh uid yang disertakan dalam token khusus. Jika akun itu sebelumnya tidak ada, catatan untuk pengguna itu akan dibuat.

Dengan cara yang sama seperti metode masuk lainnya (seperti signInWithEmailAndPassword() dan signInWithCredential() ), objek auth di Aturan Realtime Database Anda dan objek request.auth di Aturan Keamanan Cloud Storage Anda akan diisi dengan uid pengguna. Dalam hal ini, uid akan menjadi yang Anda tentukan saat membuat token khusus.

Aturan Basis Data

{
  "rules": {
    "adminContent": {
      ".read": "auth.uid === 'some-uid'"
    }
  }
}

Aturan Penyimpanan

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

Jika token kustom berisi klaim tambahan, klaim tersebut dapat dirujuk dari auth.token (Firebase Realtime Database) atau request.auth.token (Cloud Storage) dalam aturan Anda:

Aturan Basis Data

{
  "rules": {
    "premiumContent": {
      ".read": "auth.token.premiumAccount === true"
    }
  }
}

Aturan Penyimpanan

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /premiumContent/{filename} {
      allow read, write: if request.auth.token.premiumAccount == true;
    }
  }
}

Buat token khusus menggunakan perpustakaan JWT pihak ketiga

Jika backend Anda menggunakan bahasa yang tidak memiliki Firebase Admin SDK resmi, Anda masih dapat membuat token khusus secara manual. Pertama, temukan perpustakaan JWT pihak ketiga untuk bahasa Anda. Kemudian, gunakan perpustakaan JWT itu untuk mencetak JWT yang mencakup klaim berikut:

Klaim Token Kustom
alg algoritma "RS256"
iss Penerbit Alamat email akun layanan proyek Anda
sub Subjek Alamat email akun layanan proyek Anda
aud Hadirin "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Diterbitkan-pada waktu Waktu saat ini, dalam detik sejak zaman UNIX
exp waktu kedaluwarsa Waktu, dalam detik sejak zaman UNIX, saat token kedaluwarsa. Maksimal bisa 3600 detik lebih lambat dari iat .
Catatan: ini hanya mengontrol waktu ketika token khusus itu sendiri kedaluwarsa. Namun begitu Anda memasukkan pengguna menggunakan signInWithCustomToken() , mereka akan tetap masuk ke perangkat hingga sesi mereka tidak valid atau pengguna keluar.
uid Pengidentifikasi unik pengguna yang masuk harus berupa string, antara 1-36 karakter
claims (opsional) Klaim khusus opsional untuk disertakan dalam variabel auth / request.auth Aturan Keamanan

Berikut adalah beberapa contoh implementasi cara membuat token khusus dalam berbagai bahasa yang tidak didukung oleh Firebase Admin SDK:

PHP

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

Rubi

Menggunakan 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

Setelah Anda membuat token khusus, kirimkan ke aplikasi klien Anda untuk digunakan untuk mengautentikasi dengan Firebase. Lihat contoh kode di atas untuk mengetahui cara melakukannya.

Penyelesaian masalah

Bagian ini menguraikan beberapa masalah umum yang mungkin dihadapi pengembang saat membuat token khusus, dan cara mengatasinya.

IAM API tidak diaktifkan

Jika Anda menentukan ID akun layanan untuk menandatangani token, Anda mungkin mendapatkan kesalahan yang mirip dengan berikut ini:

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 menggunakan IAM API untuk menandatangani token. Kesalahan ini menunjukkan bahwa IAM API saat ini tidak diaktifkan untuk proyek Firebase Anda. Buka tautan dalam pesan kesalahan di peramban web, dan klik tombol "Aktifkan API" untuk mengaktifkannya untuk proyek Anda.

Akun layanan tidak memiliki izin yang diperlukan

Jika akun layanan yang dijalankan Firebase Admin SDK tidak memiliki izin iam.serviceAccounts.signBlob , Anda mungkin mendapatkan pesan kesalahan seperti berikut:

Permission iam.serviceAccounts.signBlob is required to perform this operation
on service account projects/-/serviceAccounts/{your-service-account-id}.

Cara termudah untuk mengatasinya adalah dengan memberikan peran IAM "Pembuat Token Akun Layanan" ke akun layanan yang dimaksud, biasanya {project-name}@appspot.gserviceaccount.com :

  1. Buka halaman IAM dan admin di Google Cloud Console.
  2. Pilih proyek Anda dan klik "Lanjutkan".
  3. Klik ikon edit yang sesuai dengan akun layanan yang ingin Anda perbarui.
  4. Klik "Tambahkan Peran Lain".
  5. Ketik "Pembuat Token Akun Layanan" ke dalam filter pencarian, dan pilih dari hasil.
  6. Klik "Simpan" untuk mengonfirmasi pemberian peran.

Lihat dokumentasi IAM untuk detail selengkapnya tentang proses ini, atau pelajari cara melakukan update peran menggunakan fitur command line gcloud.

Gagal menentukan akun layanan

Jika Anda mendapatkan pesan kesalahan yang mirip dengan berikut ini, Firebase Admin SDK belum diinisialisasi dengan benar.

Failed to determine service account ID. Initialize the SDK with service account
credentials or specify a service account ID with iam.serviceAccounts.signBlob
permission.

Jika Anda mengandalkan SDK untuk menemukan ID akun layanan secara otomatis, pastikan kode diterapkan di lingkungan Google terkelola dengan server metadata. Jika tidak, pastikan untuk menentukan file JSON akun layanan atau ID akun layanan pada inisialisasi SDK.