สร้างโทเค็นที่กำหนดเอง

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

คุณสามารถสร้างโทเค็นที่กําหนดเองด้วย Firebase Admin SDK หรือจะใช้ไลบรารี JWT ของบุคคลที่สามก็ได้หากเซิร์ฟเวอร์เขียนด้วยภาษาที่ Firebase ไม่รองรับโดยค่าเริ่มต้น

ก่อนเริ่มต้น

โทเค็นที่กำหนดเองคือ JWT ที่ลงชื่อซึ่งคีย์ส่วนตัวที่ใช้ลงชื่อเป็นของบัญชีบริการของ Google การกำหนดบัญชีบริการ Google ที่ Firebase Admin SDK ควรใช้เพื่อลงนามโทเค็นที่กำหนดเองทำได้หลายวิธี ดังนี้

  • การใช้ไฟล์ JSON ของบัญชีบริการ -- ใช้วิธีการนี้ได้ในทุกสภาพแวดล้อม แต่คุณจะต้องแพ็กเกจไฟล์ JSON ของบัญชีบริการพร้อมกับโค้ด โปรดใช้ความระมัดระวังเป็นพิเศษเพื่อให้แน่ใจว่าไฟล์ JSON ของบัญชีบริการจะไม่เปิดเผยต่อบุคคลภายนอก
  • การอนุญาตให้ Admin SDK ค้นพบบัญชีบริการ -- วิธีการนี้ใช้ได้ในสภาพแวดล้อมที่ Google เป็นผู้จัดการ เช่น Google Cloud Functions และ App Engine คุณอาจต้องกำหนดค่าสิทธิ์เพิ่มเติมบางอย่างผ่านคอนโซล Google Cloud
  • การใช้รหัสบัญชีบริการ -- เมื่อใช้ในสภาพแวดล้อมที่ Google จัดการ วิธีการนี้จะลงนามในโทเค็นโดยใช้คีย์ของบัญชีบริการที่ระบุ แต่จะใช้เว็บเซอร์วิสระยะไกล และคุณอาจต้องกำหนดค่าสิทธิ์เพิ่มเติมสำหรับบัญชีบริการนี้ผ่านคอนโซล Google Cloud

การใช้ไฟล์ JSON ของบัญชีบริการ

ไฟล์ JSON ของบัญชีบริการมีข้อมูลทั้งหมดที่เกี่ยวข้องกับบัญชีบริการ (รวมถึงคีย์ส่วนตัว RSA) โดยดาวน์โหลดได้จากคอนโซล Firebase ทำตามวิธีการตั้งค่า Admin SDK เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเริ่มต้น Admin SDK ด้วยไฟล์ JSON ของบัญชีบริการ

วิธีการเริ่มต้นนี้เหมาะสำหรับการติดตั้งใช้งาน Admin SDK หลากหลายรูปแบบ นอกจากนี้ ยังช่วยให้ Admin SDK สร้างและลงนามโทเค็นที่กำหนดเองได้ภายในเครื่องโดยไม่ต้องเรียกใช้ API จากระยะไกล ข้อเสียหลักของแนวทางนี้คือคุณต้องแพ็กเกจไฟล์ JSON ของบัญชีบริการพร้อมกับโค้ด โปรดทราบด้วยว่าคีย์ส่วนตัวในไฟล์ JSON ของบัญชีบริการเป็นข้อมูลที่ละเอียดอ่อน และต้องได้รับการดูแลเป็นพิเศษเพื่อเก็บไว้เป็นความลับ กล่าวโดยละเอียดคือ โปรดอย่าเพิ่มไฟล์ JSON ของบัญชีบริการลงในระบบควบคุมเวอร์ชันแบบสาธารณะ

การให้ Admin SDK ค้นพบบัญชีบริการ

หากทำให้โค้ดใช้งานได้ในสภาพแวดล้อมที่ Google เป็นผู้จัดการ Admin SDK จะพยายามค้นหาวิธีการลงนามโทเค็นที่กำหนดเองโดยอัตโนมัติได้ดังนี้

  • หากมีการทําให้โค้ดใช้งานได้ในApp Engineสภาพแวดล้อมมาตรฐานสําหรับ Java, Python หรือ Go นั้น Admin SDK จะใช้บริการระบุตัวตนของแอปที่มีอยู่ในสภาพแวดล้อมดังกล่าวเพื่อลงนามโทเค็นที่กําหนดเองได้ บริการระบุตัวตนของแอปจะเซ็นสัญญาข้อมูลโดยใช้บัญชีบริการที่ Google App Engine จัดสรรไว้ให้แอปของคุณ

  • หากมีการทําให้โค้ดใช้งานได้ในสภาพแวดล้อมที่มีการจัดการอื่นๆ (เช่น Google Cloud Functions, Google Compute Engine) Firebase Admin SDK จะค้นหาสตริงรหัสบัญชีบริการจากเซิร์ฟเวอร์ข้อมูลเมตาในเครื่องโดยอัตโนมัติ จากนั้นระบบจะใช้รหัสบัญชีบริการที่ค้นพบร่วมกับบริการ IAM เพื่อลงนามในโทเค็นจากระยะไกล

หากต้องการใช้วิธีการลงนามเหล่านี้ ให้เริ่มต้น SDK ด้วยข้อมูลเข้าสู่ระบบเริ่มต้นของ Google Appication และอย่าระบุสตริงรหัสบัญชีบริการ

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 ให้ชี้ไปยังไฟล์ดังกล่าว

หาก Firebase Admin SDK ต้องค้นหาสตริงรหัสบัญชีบริการ การดำเนินการนี้จะดำเนินการเมื่อโค้ดของคุณสร้างโทเค็นที่กำหนดเองเป็นครั้งแรก ผลลัพธ์จะได้รับการแคชและนำมาใช้ซ้ำสำหรับการดำเนินการลงนามโทเค็นครั้งต่อๆ ไป รหัสบัญชีบริการที่ค้นพบอัตโนมัติมักจะเป็นหนึ่งในบัญชีบริการเริ่มต้นที่ Google Cloud ระบุไว้ ดังนี้

เช่นเดียวกับรหัสบัญชีบริการที่ระบุไว้อย่างชัดเจน รหัสบัญชีบริการที่ค้นพบโดยอัตโนมัติต้องมีสิทธิ์ iam.serviceAccounts.signBlob เพื่อให้การสร้างโทเค็นที่กำหนดเองทำงานได้ คุณอาจต้องใช้ส่วน IAM และผู้ดูแลระบบของคอนโซล Google Cloud เพื่อมอบสิทธิ์ที่จําเป็นแก่บัญชีบริการเริ่มต้น โปรดดูรายละเอียดเพิ่มเติมที่ส่วนการแก้ปัญหาด้านล่าง

การใช้รหัสบัญชีบริการ

คุณสามารถระบุรหัสบัญชีบริการที่จะใช้คีย์เพื่อลงนามในโทเค็นเมื่อทํางานในสภาพแวดล้อมที่ Google จัดการ เพื่อให้แอปพลิเคชันส่วนต่างๆ ทำงานสอดคล้องกัน วิธีนี้ช่วยให้นโยบาย IAM ง่ายและปลอดภัยยิ่งขึ้น และไม่ต้องใส่ไฟล์ 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)

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สิทธิ์ โปรดดูรายละเอียดเพิ่มเติมที่ส่วนการแก้ปัญหาด้านล่าง

สร้างโทเค็นที่กำหนดเองโดยใช้ Firebase Admin SDK

Firebase Admin SDK มีเมธอดในตัวสําหรับการสร้างโทเค็นที่กําหนดเอง อย่างน้อยที่สุด คุณต้องระบุ uid ซึ่งอาจเป็นสตริงใดก็ได้ แต่ควรระบุผู้ใช้หรืออุปกรณ์ที่คุณกำลังตรวจสอบสิทธิ์ให้ระบุตัวตนได้โดยไม่ซ้ำกัน โทเค็นเหล่านี้จะหมดอายุหลังจากผ่านไป 1 ชั่วโมง

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 ที่รวมอยู่ในโทเค็นที่กำหนดเอง หากบัญชีดังกล่าวไม่เคยมีมาก่อน ระบบจะสร้างระเบียนสำหรับผู้ใช้รายนั้น

ระบบจะป้อนข้อมูล uid ของผู้ใช้ลงในออบเจ็กต์ auth ใน Realtime Database Security Rules และออบเจ็กต์ request.auth ใน Cloud Storage Security Rules ในลักษณะเดียวกับวิธีการลงชื่อเข้าใช้อื่นๆ (เช่น signInWithEmailAndPassword() และ signInWithCredential()) ในกรณีนี้ 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 เวลาที่ออก เวลาปัจจุบันเป็นวินาทีนับตั้งแต่ Epoch ของ UNIX
exp เวลาหมดอายุ เวลาเป็นวินาทีนับตั้งแต่ Epoch ของ UNIX ที่โทเค็นจะหมดอายุ โดยช้ากว่า iat ได้สูงสุด 3,600 วินาที
หมายเหตุ: การตั้งค่านี้จะควบคุมเวลาที่โทเค็นที่กำหนดเองหมดอายุเท่านั้น แต่หลังจากที่คุณลงชื่อเข้าใช้ผู้ใช้โดยใช้ signInWithCustomToken() ผู้ใช้จะยังคงลงชื่อเข้าใช้อุปกรณ์จนกว่าเซสชันจะใช้งานไม่ได้หรือผู้ใช้ออกจากระบบ
uid ตัวระบุที่ไม่ซ้ำกันของผู้ใช้ที่ลงชื่อเข้าใช้ต้องเป็นสตริงที่มีความยาวระหว่าง 1-128 อักขระ uid ที่สั้นกว่าให้ประสิทธิภาพที่ดีกว่า
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

วิธีใช้ 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 และผู้ดูแลระบบ ในคอนโซล Google Cloud
  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