Menggunakan Admin SDK dengan Data Connect

Firebase Admin SDK adalah serangkaian library server yang dapat Anda gunakan untuk berinteraksi dengan Firebase dari lingkungan istimewa untuk melakukan berbagai tindakan, seperti melakukan kueri dan mutasi pada layanan Firebase Data Connect untuk pengelolaan data massal dan operasi lainnya dengan hak istimewa yang ditingkatkan dan kredensial yang di-impersonate.

Admin SDK memberi Anda API untuk memanggil operasi dalam mode baca/tulis dan hanya baca. Dengan operasi hanya baca, Anda dapat menerapkan fungsi administratif yang tidak dapat mengubah data di database Anda dengan tenang.

Penyiapan Admin SDK

Untuk mulai menggunakan Firebase Data Connect di server, Anda harus menginstal dan menyiapkan Admin SDK untuk Node.js terlebih dahulu.

Menginisialisasi Admin SDK dalam skrip Anda

Untuk melakukan inisialisasi SDK, impor ekstensi Data Connect dan deklarasikan ID layanan dan lokasi project Anda.


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

Mendesain kueri dan mutasi untuk digunakan dengan Admin SDK

Admin SDK berguna untuk menjalankan operasi Data Connect, dengan pertimbangan berikut.

Memahami SDK dan direktif operasi @auth(level: NO_ACCESS)

Karena Admin SDK beroperasi dengan hak istimewa, Admin SDK dapat menjalankan kueri dan mutasi Anda terlepas dari tingkat akses yang ditetapkan menggunakan direktif @auth, termasuk tingkat NO_ACCESS.

Jika bersama dengan operasi klien, Anda mengatur kueri dan mutasi administratif dalam file sumber .gql untuk diimpor ke dalam skrip administratif, Firebase merekomendasikan agar Anda menandai operasi administratif tanpa tingkat akses otorisasi apa pun, atau mungkin lebih eksplisit dan menetapkannya sebagai NO_ACCESS. Bagaimanapun, hal ini mencegah operasi tersebut dijalankan dari klien atau dalam konteks non-hak istimewa lainnya.

Menggunakan SDK dengan emulator Data Connect

Di lingkungan prototipe dan pengujian, sebaiknya lakukan pengisian data dan operasi lainnya pada data lokal. Admin SDK memungkinkan Anda menyederhanakan alur kerja karena dapat mengabaikan autentikasi dan otorisasi untuk alur lokal. (Anda juga dapat secara eksplisit memilih untuk mematuhi konfigurasi autentikasi dan otorisasi operasi Anda dengan peniruan identitas pengguna.)

Firebase Admin SDK otomatis terhubung ke emulator Data Connect saat variabel lingkungan DATA_CONNECT_EMULATOR_HOST ditetapkan:

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

Untuk informasi selengkapnya, lihat:

Menjalankan operasi admin

Admin SDK disediakan untuk operasi istimewa pada data penting Anda.

Admin SDK menyediakan tiga set API:

  • Admin SDK yang dibuat, yaitu SDK yang aman untuk jenis yang dibuat dari definisi gql Anda dengan cara yang sama seperti saat Anda membuat SDK klien.
  • Antarmuka umum untuk menjalankan operasi GraphQL arbitrer, yang kode Anda mengimplementasikan kueri dan mutasi serta meneruskannya ke metode executeGraphql baca-tulis atau metode executeGraphqlRead hanya baca.
  • Antarmuka khusus untuk operasi data massal, yang bukan menggunakan metode executeGraphql generik, melainkan mengekspos metode khusus untuk operasi mutasi: insert, insertMany, upsert, dan upsertMany.

Mengelola data dengan SDK yang dibuat

Anda membuat Admin SDK dari definisi gql dengan cara yang sama seperti saat Anda membuat SDK klien.

Admin SDK yang dihasilkan berisi antarmuka dan fungsi yang sesuai dengan definisi gql Anda, yang dapat Anda gunakan untuk melakukan operasi pada database Anda. Misalnya, Anda membuat SDK untuk database lagu, beserta kueri, 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 } }
);

Atau, untuk menentukan konfigurasi konektor:

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

Meniru identitas pengguna yang tidak diautentikasi

Admin SDK dimaksudkan untuk dijalankan dari lingkungan tepercaya, dan oleh karena itu memiliki akses tidak terbatas ke database Anda.

Saat menjalankan operasi publik dengan Admin SDK, Anda harus menghindari menjalankan operasi dengan hak istimewa administrator penuh (mengikuti prinsip hak istimewa terendah). Sebagai gantinya, Anda harus menjalankan operasi sebagai pengguna yang di-impersonate (lihat bagian berikutnya), atau sebagai pengguna tidak terautentikasi yang di-impersonate. Pengguna yang tidak diautentikasi hanya dapat menjalankan operasi yang ditandai sebagai PUBLIC.

Dalam contoh di atas, kueri getSongs dijalankan sebagai pengguna yang tidak diautentikasi.

Meniru identitas pengguna

Anda juga dapat melakukan operasi atas nama pengguna tertentu dengan meneruskan sebagian atau seluruh token Firebase Authentication dalam opsi impersonate; minimal, Anda harus menentukan ID pengguna di sub-klaim. (Nilai ini sama dengan nilai server auth.uid yang dapat Anda rujuk dalam operasi GraphQL Data Connect.)

Saat Anda meniru identitas pengguna, operasi hanya akan berhasil jika data pengguna yang Anda berikan lulus pemeriksaan autentikasi yang ditentukan dalam definisi GraphQL Anda.

Jika Anda memanggil SDK yang dihasilkan dari endpoint yang dapat diakses secara publik, endpoint tersebut harus memerlukan autentikasi dan Anda harus memvalidasi integritas token autentikasi sebelum menggunakannya untuk meniru identitas pengguna.

Saat menggunakan Cloud Functions yang dapat dipanggil, token autentikasi akan diverifikasi secara otomatis dan Anda dapat menggunakannya seperti dalam contoh berikut:

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

    // ...
});

Jika tidak, gunakan metode verifyIdToken dari Admin SDK untuk memvalidasi dan mendekode token autentikasi. Misalnya, endpoint Anda diimplementasikan sebagai fungsi HTTP biasa dan Anda telah meneruskan token Firebase Authentication ke endpoint menggunakan header authorization, seperti standar:

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

    // ...
});

Hanya saat melakukan tugas administratif yang sebenarnya, seperti migrasi data, dari lingkungan yang aman dan tidak dapat diakses secara publik, Anda harus menentukan ID pengguna yang tidak berasal dari sumber yang dapat diverifikasi:

// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
  undefined,
  { impersonate: { authClaims } }
);

Menjalankan dengan akses tidak terbatas

Jika Anda melakukan operasi yang memerlukan izin tingkat admin, hapus parameter peniruan identitas dari panggilan:

await upsertSong(adminDc, {
  title: songTitle_one,
  instrumentsUsed: [Instrument.VOCAL],
});

Operasi yang dipanggil dengan cara ini memiliki akses penuh ke database. Jika Anda memiliki kueri atau mutasi yang hanya dimaksudkan untuk digunakan untuk tujuan administrasi, Anda harus menentukannya dengan direktif @auth(level: NO_ACCESS). Dengan demikian, hanya pemanggil tingkat admin yang dapat menjalankan operasi ini.

Mengelola data dengan metode executeGraphql

Jika Anda perlu menjalankan operasi sekali pakai yang belum Anda tentukan mutasi atau kuerinya, Anda dapat menggunakan metode executeGraphql atau metode executeGraphqlRead baca saja.gql

Meniru identitas pengguna yang tidak diautentikasi

Saat menjalankan operasi publik dengan Admin SDK, Anda harus menghindari menjalankan operasi dengan hak istimewa administrator penuh (mengikuti prinsip hak istimewa terendah). Sebagai gantinya, Anda harus menjalankan operasi sebagai pengguna yang di-impersonate (lihat bagian berikutnya), atau sebagai pengguna yang di-impersonate yang tidak terautentikasi. Pengguna yang tidak diautentikasi hanya dapat menjalankan operasi yang ditandai sebagai 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);

Meniru identitas pengguna

Ada juga kasus penggunaan saat Anda ingin skrip mengubah data pengguna berdasarkan kredensial terbatas, atas nama pengguna tertentu. Pendekatan ini mematuhi prinsip hak istimewa terendah.

Untuk menggunakan antarmuka ini, kumpulkan informasi dari token autentikasi JWT yang disesuaikan yang mengikuti format token Authentication. Lihat juga panduan token kustom.

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

Menggunakan kredensial administratif

Jika Anda melakukan operasi yang memerlukan izin tingkat admin, hapus parameter peniruan identitas dari panggilan:

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

Operasi yang dipanggil dengan cara ini memiliki akses penuh ke database. Jika Anda memiliki kueri atau mutasi yang hanya dimaksudkan untuk digunakan untuk tujuan administrasi, Anda harus menentukannya dengan direktif @auth(level: NO_ACCESS). Dengan demikian, hanya pemanggil tingkat admin yang dapat menjalankan operasi ini.

Melakukan operasi data massal

Firebase merekomendasikan Anda menggunakan Admin SDK untuk operasi data massal di database produksi.

SDK menyediakan metode berikut untuk menangani data massal. Dari argumen yang diberikan, setiap metode membuat dan menjalankan mutasi GraphQL.


// Methods of the bulk operations API
// dc is a Data 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);

Catatan performa untuk operasi massal

Setiap permintaan ke backend akan menimbulkan satu perjalanan pulang pergi ke Cloud SQL, sehingga semakin banyak yang Anda batch, semakin tinggi throughput-nya.

Namun, makin besar ukuran batch, makin panjang pernyataan SQL yang dihasilkan. Jika batas panjang pernyataan SQL PostgreSQL tercapai, Anda akan mengalami error.

Dalam praktiknya, lakukan eksperimen untuk menemukan ukuran batch yang sesuai untuk beban kerja Anda.

Apa langkah selanjutnya?