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

Firebase ช่วยให้คุณควบคุมการตรวจสอบสิทธิ์ได้อย่างสมบูรณ์โดยอนุญาตให้คุณตรวจสอบสิทธิ์ผู้ใช้หรืออุปกรณ์โดยใช้ JSON Web Token (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 ควรใช้เพื่อลงชื่อโทเค็นที่กำหนดเองได้หลายวิธี ดังนี้

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

เราขอแนะนำ 2 วิธีแรกเนื่องจากคุณไม่จำเป็นต้องดาวน์โหลดหรือจัดการคีย์บัญชีบริการ

การอนุญาตให้ 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 และไม่ต้องระบุสตริงรหัสบัญชีบริการ ดังนี้

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

หากต้องการทดสอบโค้ดเดียวกันในเครื่องโดยไม่ต้องดาวน์โหลดคีย์บัญชีบริการ ให้ลงชื่อเข้าใช้ด้วยข้อมูลเข้าสู่ระบบของผู้ใช้ของคุณเองโดยใช้ Google Cloud CLI ดังนี้

gcloud auth application-default login

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

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

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

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

คุณสามารถระบุรหัสบัญชีบริการที่จะใช้คีย์ที่ Google จัดการเพื่อลงชื่อโทเค็นได้ เพื่อรักษาความสอดคล้องกันระหว่างส่วนต่างๆ ของแอปพลิเคชัน ซึ่งจะช่วยให้นโยบาย IAM ง่ายขึ้นและปลอดภัยยิ่งขึ้น รวมถึงหลีกเลี่ยงการดาวน์โหลด จัดเก็บ หรือติดตั้งใช้งานคีย์บัญชีบริการ

คุณดูรหัสบัญชีบริการได้ในคอนโซล Google Cloud รหัสบัญชีบริการคืออีเมลที่มีรูปแบบดังนี้ <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 ดูรายละเอียดเพิ่มเติมได้ที่ส่วนการแก้ปัญหาด้านล่าง

การใช้ไฟล์คีย์บัญชีบริการ

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

คีย์บัญชีบริการเป็นข้อมูลเข้าสู่ระบบที่มีอายุการใช้งานยาวนาน หากคีย์รั่วไหล ทุกคนที่มีคีย์จะทำหน้าที่เป็นบัญชีบริการได้จนกว่าคีย์จะถูกลบ อย่าคอมมิตไฟล์คีย์ไปยังการควบคุมเวอร์ชัน และพิจารณาใช้ Workload Identity Federation แทนคีย์ในกรณีที่สภาพแวดล้อมของคุณรองรับ นอกจากนี้ โปรดทราบว่าบางองค์กรใช้ข้อจำกัดด้านนโยบายขององค์กรเพื่อป้องกันการสร้างคีย์บัญชีบริการ ซึ่งในกรณีนี้คุณต้องใช้วิธีอื่น

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

เช่นเดียวกับวิธีการลงชื่อเข้าใช้อื่นๆ (เช่น 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 ของบุคคลที่สาม

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

การอ้างสิทธิ์โทเค็นที่กำหนดเอง
alg อัลกอริทึม "RS256"
iss ผู้ออก อีเมลบัญชีบริการของโปรเจ็กต์
sub เรื่อง อีเมลบัญชีบริการของโปรเจ็กต์
aud กลุ่มเป้าหมาย "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat เวลาที่ออก เวลาปัจจุบันในหน่วยวินาทีตั้งแต่ Unix Epoch
exp เวลาหมดอายุ เวลาที่โทเค็นหมดอายุในหน่วยวินาทีนับตั้งแต่ Unix Epoch โดยต้อง ช้ากว่า iat ไม่เกิน 3,600 วินาที
หมายเหตุ: การดำเนินการนี้จะควบคุมเฉพาะเวลาที่โทเค็นที่กำหนดเองหมดอายุเท่านั้น แต่เมื่อคุณลงชื่อเข้าใช้ให้ผู้ใช้โดยใช้ signInWithCustomToken() ผู้ใช้จะยังคงลงชื่อเข้าใช้อุปกรณ์อยู่จนกว่าเซสชันจะใช้งานไม่ได้หรือผู้ใช้ลงชื่อออก
uid ตัวระบุที่ไม่ซ้ำกันของผู้ใช้ที่ลงชื่อเข้าใช้ต้องเป็นสตริงที่มีความยาวระหว่าง 1-128 อักขระ (รวมค่าขอบเขต) uid ที่สั้นกว่าจะให้ประสิทธิภาพที่ดีกว่า
claims (ไม่บังคับ) การอ้างสิทธิ์ที่กำหนดเอง (ไม่บังคับ) ที่จะรวมไว้ในตัวแปร auth / request.auth ของกฎความปลอดภัย

ต่อไปนี้คือตัวอย่างการติดตั้งใช้งานวิธีสร้างโทเค็นที่กำหนดเองในภาษาต่างๆ ที่ Firebase Admin SDK ไม่รองรับ ตัวอย่างเหล่านี้จะลงชื่อโทเค็นในเครื่องด้วยคีย์ส่วนตัวของบัญชีบริการ ดังนั้นคำแนะนำด้านความปลอดภัยสำหรับไฟล์คีย์บัญชีบริการจึงมีผลบังคับใช้ หากต้องการหลีกเลี่ยงการจัดการคีย์ส่วนตัว คุณสามารถให้ Google ลงชื่อในเพย์โหลดโทเค็นจากระยะไกลแทนได้โดยเรียกใช้เมธอด signJwt ของ IAM Service Account Credentials API ผู้เรียกต้องมีบทบาทผู้สร้างโทเค็นบัญชีบริการในบัญชีบริการ

PHP

การใช้ php-jwt:

// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;

// Placeholder values. In production, load your service account's email
// address and private key from a secure secret store. Never hard-code
// private keys in source code.
$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"

# Placeholder values. In production, load your service account's email
# address and private key from a secure secret store. Never hard-code
# private keys in source code.
$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" เพื่อเปิดใช้ 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 ผู้สร้างโทเค็นบัญชีบริการให้กับบัญชีบริการที่เหมาะสม บัญชีบริการเริ่มต้นที่ใช้จะขึ้นอยู่กับสภาพแวดล้อมและเวอร์ชันของ Cloud Functions ดังนี้

  • Cloud Functions (รุ่นที่ 1): ใช้บัญชีบริการ App Engine เริ่มต้น
  • Cloud Functions (รุ่นที่ 2): ใช้บัญชีบริการ Compute Engine เริ่มต้น
  1. ในคอนโซล Google Cloud ให้ไปที่ IAM และผู้ดูแลระบบ

  2. คลิกไอคอนแก้ไขที่ตรงกับบัญชีบริการที่ต้องการอัปเดต

  3. คลิกเพิ่มบทบาทอื่น

  4. พิมพ์ "Service Account Token Creator" ลงในตัวกรองการค้นหา แล้วเลือกจากผลการค้นหา

  5. คลิกบันทึกเพื่อยืนยันการให้บทบาท

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