Firebase Admin SDK คือชุดไลบรารีเซิร์ฟเวอร์ที่ช่วยให้คุณโต้ตอบกับ Firebase จากสภาพแวดล้อมที่มีสิทธิ์เพื่อดำเนินการต่างๆ เช่น การค้นหาและการเปลี่ยนแปลงในบริการ Firebase SQL Connect สำหรับการจัดการข้อมูลจำนวนมากและการดำเนินการอื่นๆ ที่มีสิทธิ์ในระดับสูงขึ้นและข้อมูลเข้าสู่ระบบที่แอบอ้าง
Admin SDK มี API สำหรับเรียกใช้การดำเนินการทั้งในโหมดอ่าน/เขียนและโหมดอ่านอย่างเดียว การดำเนินการแบบอ่านอย่างเดียวช่วยให้คุณอุ่นใจได้เมื่อใช้ฟังก์ชันการดูแลระบบที่ไม่สามารถแก้ไขข้อมูลในฐานข้อมูลได้
การตั้งค่า Admin SDK
หากต้องการเริ่มใช้ Firebase SQL Connect บนเซิร์ฟเวอร์ คุณจะต้องติดตั้งและตั้งค่า Admin SDK สำหรับ Node.js ก่อน
เริ่มต้น Admin SDK ในสคริปต์
หากต้องการเริ่มต้น SDK ให้ใช้ส่วนขยาย SQL Connect และประกาศรหัสบริการและตำแหน่งของโปรเจ็กต์
import { initializeApp } from 'firebase-admin/app';
import { getDataConnect } from 'firebase-admin/data-connect';
// If you'd like to use OAuth2 flows and other credentials to log in,
// visit https://firebase.google.com/docs/admin/setup#initialize-sdk
// for alternative ways to initialize the SDK.
const app = initializeApp();
const dataConnect = getDataConnect({
serviceId: 'serviceId',
location: 'us-west2'
});
ออกแบบการค้นหาและการเปลี่ยนแปลงเพื่อใช้กับ Admin SDK
Admin SDK มีประโยชน์สำหรับการดำเนินการ SQL Connect โดยพิจารณาจากข้อควรพิจารณาต่อไปนี้
ทำความเข้าใจ SDK และคำสั่งการดำเนินการ @auth(level: NO_ACCESS)
เนื่องจาก Admin SDK ทำงานด้วยสิทธิ์ จึงสามารถเรียกใช้การค้นหาและการเปลี่ยนแปลงใดๆ ของคุณได้ ไม่ว่าระดับการเข้าถึงจะตั้งค่าโดยใช้คำสั่ง @auth รวมถึงระดับ NO_ACCESS ก็ตาม
หากคุณจัดระเบียบการค้นหาและการเปลี่ยนแปลงด้านการดูแลระบบในไฟล์ต้นฉบับ .gql เพื่อนำเข้าสคริปต์ด้านการดูแลระบบควบคู่ไปกับการดำเนินการของไคลเอ็นต์ Firebase ขอแนะนำให้คุณทำเครื่องหมายการดำเนินการด้านการดูแลระบบโดยไม่มีระดับการเข้าถึงการให้สิทธิ์ หรืออาจระบุให้ชัดเจนยิ่งขึ้นและตั้งค่าเป็น NO_ACCESS ไม่ว่าจะด้วยวิธีใด การดำเนินการนี้จะป้องกันไม่ให้มีการดำเนินการดังกล่าวจากไคลเอ็นต์หรือในบริบทอื่นๆ ที่ไม่มีสิทธิ์
ใช้ SDK กับโปรแกรมจำลอง SQL Connect
ในสภาพแวดล้อมต้นแบบและการทดสอบ การสร้างข้อมูลและการดำเนินการอื่นๆ กับข้อมูลในเครื่องอาจเป็นประโยชน์ Admin SDK ช่วยให้คุณลดความซับซ้อนของเวิร์กโฟลว์ได้เนื่องจากสามารถข้ามการตรวจสอบสิทธิ์และการให้สิทธิ์สำหรับโฟลว์ในเครื่อง (นอกจากนี้ คุณยังเลือกใช้การปฏิบัติตามการกำหนดค่าการตรวจสอบสิทธิ์และการให้สิทธิ์ของการดำเนินการด้วยการสวมบทบาทเป็นผู้ใช้ได้อย่างชัดเจน)
Firebase Admin SDK จะเชื่อมต่อกับโปรแกรมจำลอง SQL Connect โดยอัตโนมัติเมื่อตั้งค่าตัวแปรสภาพแวดล้อม DATA_CONNECT_EMULATOR_HOST ดังนี้
export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"
ดูข้อมูลเพิ่มเติมได้ที่
เรียกใช้การดำเนินการของผู้ดูแลระบบ
Admin SDKมีไว้สำหรับการดำเนินการที่มีสิทธิ์ในข้อมูลสำคัญของคุณ
Admin SDK มี API 3 ชุด ได้แก่
- Admin SDK ที่สร้างขึ้น ซึ่งเป็น SDK ที่ปลอดภัยในการกำหนดประเภทที่สร้างขึ้นจากคำจำกัดความ
gqlในลักษณะเดียวกับที่คุณสร้าง SDK ของไคลเอ็นต์ - อินเทอร์เฟซทั่วไปสำหรับการเรียกใช้การดำเนินการ GraphQL โดยพลการ ซึ่งโค้ดของคุณจะใช้การค้นหาและการกลายพันธุ์ และส่งไปยังเมธอด
executeGraphqlแบบอ่าน-เขียน หรือเมธอดexecuteGraphqlReadแบบอ่านอย่างเดียว - อินเทอร์เฟซเฉพาะสำหรับการดำเนินการกับข้อมูลจำนวนมาก ซึ่งจะแสดงเมธอดเฉพาะสำหรับการดำเนินการเปลี่ยนแปลง ได้แก่
insert,insertMany,upsertและupsertManyแทนเมธอดexecuteGraphqlทั่วไป
จัดการข้อมูลด้วย SDK ที่สร้างขึ้น
คุณสร้าง Admin SDK จากคำจำกัดความ gql ในลักษณะเดียวกับที่สร้าง SDK ของไคลเอ็นต์
Admin SDK ที่สร้างขึ้นประกอบด้วยอินเทอร์เฟซและฟังก์ชันที่สอดคล้องกับคำจำกัดความ gql ของคุณ ซึ่งคุณสามารถใช้เพื่อดำเนินการกับฐานข้อมูลได้ ตัวอย่างเช่น สมมติว่าคุณสร้าง SDK สำหรับฐานข้อมูลเพลงพร้อมกับคำค้นหา getSongs ดังนี้
import { initializeApp } from "firebase-admin/app";
import { getSongs } from "@dataconnect/admin-generated";
const adminApp = initializeApp();
const songs = await getSongs(
{ limit: 4 },
{ impersonate: { unauthenticated: true } }
);
หรือหากต้องการระบุการกำหนดค่าเครื่องมือเชื่อมต่อ ให้ทำดังนี้
import { initializeApp } from "firebase-admin/app";
import { getDataConnect } from "firebase-admin/data-connect";
import {
connectorConfig,
getSongs,
} from "@dataconnect/admin-generated";
const adminApp = initializeApp();
const adminDc = getDataConnect(connectorConfig);
const songs = await getSongs(
adminDc,
{ limit: 4 },
{ impersonate: { unauthenticated: true } }
);
การแอบอ้างเป็นผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์
Admin SDK มีไว้เพื่อเรียกใช้จากสภาพแวดล้อมที่เชื่อถือได้ จึงมีสิทธิ์เข้าถึงฐานข้อมูลของคุณแบบไม่จำกัด
เมื่อเรียกใช้การดำเนินการสาธารณะด้วย Admin SDK คุณควรหลีกเลี่ยงการเรียกใช้การดำเนินการด้วยสิทธิ์ของผู้ดูแลระบบเต็มรูปแบบ (ตามหลักการให้สิทธิ์ขั้นต่ำที่สุด) แต่คุณควรเรียกใช้การดำเนินการในฐานะผู้ใช้ที่ถูกแอบอ้าง (ดูส่วนถัดไป) หรือในฐานะผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์ที่ถูกแอบอ้าง
ผู้ใช้ที่ไม่ผ่านการตรวจสอบสิทธิ์จะเรียกใช้ได้เฉพาะการดำเนินการที่ทำเครื่องหมายเป็น PUBLIC เท่านั้น
ในตัวอย่างข้างต้น การค้นหา getSongs จะดำเนินการในฐานะผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์
การแอบอ้างเป็นผู้ใช้
นอกจากนี้ คุณยังดำเนินการในนามของผู้ใช้ที่เฉพาะเจาะจงได้โดยส่งโทเค็น Firebase Authentication บางส่วนหรือทั้งหมดในตัวเลือก impersonate โดยอย่างน้อยที่สุด คุณต้องระบุรหัสผู้ใช้ของผู้ใช้ในการอ้างสิทธิ์ย่อย (ค่านี้เป็นค่าเดียวกับค่าเซิร์ฟเวอร์ auth.uid ที่คุณอ้างอิงได้ในการดำเนินการ GraphQL SQL Connect)
เมื่อคุณแอบอ้างเป็นผู้ใช้ การดำเนินการจะสำเร็จก็ต่อเมื่อข้อมูลผู้ใช้ที่คุณระบุผ่านการตรวจสอบการตรวจสอบสิทธิ์ที่ระบุไว้ในคำจำกัดความ GraphQL ของคุณ
หากคุณเรียกใช้ SDK ที่สร้างขึ้นจากปลายทางที่เข้าถึงได้แบบสาธารณะ คุณจำเป็นต้องกำหนดให้ปลายทางต้องมีการตรวจสอบสิทธิ์ และคุณต้องตรวจสอบความถูกต้องของโทเค็นการตรวจสอบสิทธิ์ก่อนที่จะใช้เพื่อแอบอ้างเป็นผู้ใช้
เมื่อใช้ Cloud Functions ที่เรียกใช้ได้ ระบบจะยืนยันโทเค็นการตรวจสอบสิทธิ์โดยอัตโนมัติ และคุณสามารถใช้โทเค็นดังกล่าวได้ดังตัวอย่างต่อไปนี้
import { HttpsError, onCall } from "firebase-functions/https";
export const callableExample = onCall(async (req) => {
const authClaims = req.auth?.token;
if (!authClaims) {
throw new HttpsError("unauthenticated", "Unauthorized");
}
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
// ...
});
หรือใช้วิธี verifyIdToken ของ Admin SDK เพื่อตรวจสอบและถอดรหัสโทเค็นการตรวจสอบสิทธิ์ ตัวอย่างเช่น สมมติว่าปลายทางของคุณใช้เป็นฟังก์ชัน HTTP ธรรมดา และคุณได้ส่งโทเค็น Firebase Authentication ไปยังปลายทางโดยใช้ส่วนหัว authorization ตามมาตรฐาน ดังนี้
import { getAuth } from "firebase-admin/auth";
import { onRequest } from "firebase-functions/https";
const auth = getAuth();
export const httpExample = onRequest(async (req, res) => {
const token = req.header("authorization")?.replace(/^bearer\s+/i, "");
if (!token) {
res.sendStatus(401);
return;
}
let authClaims;
try {
authClaims = await auth.verifyIdToken(token);
} catch {
res.sendStatus(401);
return;
}
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
// ...
});
คุณควรระบุรหัสผู้ใช้ที่ไม่ได้มาจากแหล่งที่มาที่ยืนยันได้เฉพาะเมื่อดำเนินการด้านการดูแลระบบอย่างแท้จริง เช่น การย้ายข้อมูล จากสภาพแวดล้อมที่ปลอดภัยและไม่สามารถเข้าถึงได้แบบสาธารณะเท่านั้น
// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
ทำงานโดยมีสิทธิ์เข้าถึงแบบไม่จำกัด
หากคุณกำลังดำเนินการที่ต้องใช้สิทธิ์ระดับผู้ดูแลระบบ ให้ละเว้นพารามิเตอร์การแอบอ้างเป็นบุคคลอื่นจากการเรียกใช้ ดังนี้
await upsertSong(adminDc, {
title: songTitle_one,
instrumentsUsed: [Instrument.VOCAL],
});
การดำเนินการที่เรียกใช้ในลักษณะนี้จะมีสิทธิ์เข้าถึงฐานข้อมูลอย่างสมบูรณ์ หากคุณมีคำค้นหาหรือการเปลี่ยนแปลงที่ตั้งใจจะใช้เพื่อวัตถุประสงค์ด้านการดูแลระบบเท่านั้น คุณควรกำหนดคำค้นหาหรือการเปลี่ยนแปลงเหล่านั้นด้วยคำสั่ง @auth(level: NO_ACCESS) การดำเนินการนี้ช่วยให้มั่นใจได้ว่ามีเพียงผู้โทรระดับผู้ดูแลระบบเท่านั้นที่สามารถดำเนินการเหล่านี้ได้
จัดการข้อมูลด้วยเมธอด executeGraphql
หากต้องการดำเนินการแบบครั้งเดียวซึ่งคุณไม่ได้กำหนดการเปลี่ยนแปลงหรือการค้นหา gql ไว้ คุณสามารถใช้เมธอด executeGraphql หรือเมธอด executeGraphqlRead แบบอ่านอย่างเดียวได้
ดำเนินการเชิงสัมพันธ์ที่ซ้อนกันแบบกำหนดเอง (1 ต่อหลายและ 1 ต่อ 1) โดยใช้ executeGraphql
เมื่อเรียกใช้การดำเนินการจาก Admin SDK ในสภาพแวดล้อมที่มีสิทธิ์ คุณไม่จำเป็นต้องระบุคำสั่ง @allow ในตัวแปรสำหรับการแทรกแบบแบนมาตรฐาน (ไม่ซ้อนกัน) (เช่น การแทรกระเบียนภาพยนตร์หรือนักแสดงแต่ละรายการ)
อย่างไรก็ตาม สำหรับการแทรกเชิงสัมพันธ์ที่ซ้อนกัน (เช่น การแทรกภาพยนตร์พร้อมกับรีวิวเริ่มต้น หรือผู้ใช้และโปรไฟล์ของผู้ใช้) คุณยังคงต้องประกาศคำสั่ง @allow ในคำจำกัดความของตัวแปรเพื่ออนุญาตฟิลด์เชิงสัมพันธ์ที่ซ้อนกันภายในสคีมาตัวแปรที่คอมไพล์แล้วแบบคงที่
// Custom GraphQL mutation with nested relational insert (one-to-many)
const customMutation = `
mutation CustomBatchInsert(
$data: [Movie_Data!]!
@allow(fields: "title genre reviews_on_movie { rating reviewText }")
) {
movie_insertMany(data: $data)
}
`;
const variables = {
data: [
{
title: "Interstellar",
genre: "Sci-Fi",
reviews_on_movie: [
{
rating: 5,
reviewText: "Visually stunning and emotionally powerful.",
user: { id: "user-789" }
}
]
}
]
};
const response = await dataConnect.executeGraphql(customMutation, { variables });
// Custom GraphQL mutation with a one-to-one nested relational insert
const customMutationOneToOne = `
mutation CustomBatchInsertOneToOne(
$data: [User_Data!]!
@allow(fields: "name profile_on_user { bio }")
) {
user_insertMany(data: $data)
}
`;
const variablesOneToOne = {
data: [
{
name: "Alice",
profile_on_user: {
bio: "Avid moviegoer and critic."
}
}
]
};
const responseOneToOne = await dataConnect.executeGraphql(customMutationOneToOne, { variables: variablesOneToOne });
การแอบอ้างเป็นผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์
เมื่อเรียกใช้การดำเนินการสาธารณะด้วย Admin SDK คุณควรหลีกเลี่ยงการเรียกใช้การดำเนินการด้วยสิทธิ์ของผู้ดูแลระบบเต็มรูปแบบ (ตามหลักการให้สิทธิ์ขั้นต่ำที่สุด) แต่คุณควรเรียกใช้การดำเนินการในฐานะผู้ใช้ที่ถูกแอบอ้าง (ดูส่วนถัดไป) หรือในฐานะผู้ใช้ที่ไม่ได้รับการตรวจสอบสิทธิ์ที่ถูกแอบอ้าง ผู้ใช้ที่ไม่ผ่านการตรวจสอบสิทธิ์จะเรียกใช้ได้เฉพาะการดำเนินการที่ทำเครื่องหมายเป็น PUBLIC เท่านั้น
// Query to get posts, with authentication level PUBLIC
const queryGetPostsImpersonation = `
query getPosts @auth(level: PUBLIC) {
posts {
description
}
}`;
// Attempt to access data as an unauthenticated user
const optionsUnauthenticated: GraphqlOptions<undefined> = {
impersonate: {
unauthenticated: true
}
};
// executeGraphql with impersonated unauthenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetPostsImpersonation, optionsUnauthenticated);
การแอบอ้างเป็นผู้ใช้
นอกจากนี้ยังมี Use Case ที่คุณต้องการให้สคริปต์แก้ไขข้อมูลผู้ใช้โดยอิงตามข้อมูลเข้าสู่ระบบแบบจำกัดในนามของผู้ใช้ที่เฉพาะเจาะจง วิธีนี้เป็นไปตามหลักการให้สิทธิ์ขั้นต่ำที่สุด
หากต้องการใช้อินเทอร์เฟซนี้ ให้รวบรวมข้อมูลจากโทเค็นการตรวจสอบสิทธิ์ JWT ที่กำหนดเองซึ่งเป็นไปตามรูปแบบโทเค็น Authentication นอกจากนี้ โปรดดูคู่มือโทเค็นที่กำหนดเองด้วย
// Get the current user's data
const queryGetUserImpersonation = `
query getUser @auth(level: USER) {
user(key: {uid_expr: "auth.uid"}) {
id,
name
}
}`;
// Impersonate a user with the specified auth claims
const optionsAuthenticated: GraphqlOptions<undefined> = {
impersonate: {
authClaims: {
sub: 'QVBJcy5ndXJ1'
}
}
};
// executeGraphql with impersonated authenticated user scope
const gqlResponse = await dataConnect.executeGraphql<UserData, undefined>(queryGetUserImpersonation, optionsAuthenticated);
// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }
ใช้ข้อมูลเข้าสู่ระบบของผู้ดูแลระบบ
หากคุณกำลังดำเนินการที่ต้องใช้สิทธิ์ระดับผู้ดูแลระบบ ให้ละเว้นพารามิเตอร์การแอบอ้างเป็นบุคคลอื่นจากการเรียกใช้ ดังนี้
// User can be publicly accessible, or restricted to admins
const query = "query getProfile(id: AuthID) { user(id: $id) { id name } }";
interface UserData {
user: {
id: string;
name: string;
};
}
export interface UserVariables {
id: string;
}
const options:GraphqlOptions<UserVariables> = { variables: { id: "QVBJcy5ndXJ1" } };
// executeGraphql
const gqlResponse = await dataConnect.executeGraphql<UserData, UserVariables>(query, options);
// executeGraphqlRead (similar to previous sample but only for read operations)
const gqlResponse = await dataConnect.executeGraphqlRead<UserData, UserVariables>(query, options);
// gqlResponse -> { "data": { "user": { "id": "QVBJcy5ndXJ1", "name": "Fred" } } }
การดำเนินการที่เรียกใช้ในลักษณะนี้จะมีสิทธิ์เข้าถึงฐานข้อมูลอย่างสมบูรณ์ หากคุณมีคำค้นหาหรือการเปลี่ยนแปลงที่ตั้งใจจะใช้เพื่อวัตถุประสงค์ด้านการดูแลระบบเท่านั้น คุณควรกำหนดคำค้นหาหรือการเปลี่ยนแปลงเหล่านั้นด้วยคำสั่ง @auth(level: NO_ACCESS) การดำเนินการนี้ช่วยให้มั่นใจได้ว่ามีเพียงผู้โทรระดับผู้ดูแลระบบเท่านั้นที่สามารถดำเนินการเหล่านี้ได้
ดำเนินการแทรกข้อมูลจำนวนมาก
Firebase ขอแนะนำให้คุณใช้ Admin SDK สำหรับการดำเนินการกับข้อมูลจำนวนมากในฐานข้อมูลเวอร์ชันที่ใช้งานจริง
SDK มีเมธอดต่อไปนี้สำหรับการทำงานกับข้อมูลจำนวนมาก จากอาร์กิวเมนต์ที่ระบุ แต่ละเมธอดจะสร้างและดำเนินการ Mutation ของ GraphQL
// Methods of the bulk operations API
// dc is a SQL Connect admin instance from getDataConnect
const resp = await dc.insert("movie" /*table name*/, data[0]);
const resp = await dc.insertMany("movie" /*table name*/, data);
const resp = await dc.upsert("movie" /*table name*/, data[0]);
const resp = await dc.upsertMany("movie" /*table name*/, data);
การดำเนินการเชิงสัมพันธ์ที่ซ้อนกัน (1 ต่อหลายและ 1 ต่อ 1)
Admin SDK รองรับข้อมูลเชิงสัมพันธ์ในการดำเนินการแบบกลุ่ม เช่นเดียวกับการกลายพันธุ์ที่กำหนดเอง ให้ใช้อาร์เรย์ของออบเจ็กต์สำหรับความสัมพันธ์แบบ 1 ต่อหลาย และออบเจ็กต์เดียวสำหรับความสัมพันธ์แบบ 1 ต่อ 1 ดังนี้
// Example of inserting a movie with nested reviews (one-to-many)
const moviesData = [
{
title: "Interstellar",
genre: "Sci-Fi",
reviews_on_movie: [
{
rating: 5,
reviewText: "Visually stunning and emotionally powerful.",
user: { id: "user-789" }
}
]
}
];
// Atomically insert movies and their reviews in a single database round-trip.
const response = await dc.insertMany("movie", moviesData);
// Example of inserting a user with a nested profile (one-to-one)
const usersData = [
{
name: "Alice",
profile_on_user: {
bio: "Avid moviegoer and critic."
}
}
];
// Atomically insert users and their profiles.
const userResponse = await dc.insertMany("user", usersData);
หมายเหตุเกี่ยวกับประสิทธิภาพสำหรับการดำเนินการแบบกลุ่ม
คำขอแต่ละรายการที่ส่งไปยังแบ็กเอนด์จะทำให้เกิดการส่งไปกลับ 1 ครั้งไปยัง Cloud SQL ดังนั้นยิ่งคุณรวมกลุ่มมากเท่าใด ปริมาณงานก็จะยิ่งสูงขึ้นเท่านั้น
อย่างไรก็ตาม ยิ่งขนาดกลุ่มใหญ่เท่าใด คำสั่ง SQL ที่สร้างขึ้นก็จะยิ่งยาวขึ้นเท่านั้น เมื่อถึงขีดจำกัดความยาวของคำสั่ง SQL ของ PostgreSQL คุณจะพบข้อผิดพลาด
ในทางปฏิบัติ ให้ทดลองเพื่อหาขนาดกลุ่มที่เหมาะสมสำหรับภาระงานของคุณ
ต้องทำอะไรต่อ
- ดูข้อมูลเกี่ยวกับการสร้างฐานข้อมูลด้วยข้อมูลโดยใช้ Admin SDK
- ตรวจสอบ API สำหรับ Admin SDK
- ใช้ Firebase CLI และคอนโซล Google Cloud สำหรับการดำเนินการจัดการโปรเจ็กต์อื่นๆ เช่น การจัดการสคีมาและเครื่องมือเชื่อมต่อ และการจัดการบริการและฐานข้อมูล