Menggunakan Admin SDK dengan SQL Connect

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

Admin SDK menyediakan 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 dengan Firebase SQL Connect di server Anda, Anda harus menginstal dan menyiapkan Admin SDK untuk Node.js terlebih dahulu.

Menginisialisasi Admin SDK dalam skrip Anda

Untuk menginisialisasi SDK, impor ekstensi SQL Connect dan deklarasikan ID layanan project dan lokasi 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 SQL Connect, dengan pertimbangan berikut.

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

Karena Admin SDK beroperasi dengan hak istimewa, SDK ini dapat menjalankan kueri dan mutasi Anda, terlepas dari tingkat akses yang ditetapkan menggunakan @auth direktif, 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. Dengan cara apa pun, hal ini mencegah operasi tersebut dijalankan dari klien atau dalam konteks non-istimewa lainnya.

Menggunakan SDK dengan emulator SQL Connect

Di lingkungan prototipe dan pengujian, melakukan seeding data dan operasi lainnya pada data lokal dapat berguna. 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 SQL Connect emulator 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 kumpulan API:

  • Admin SDK yang dibuat, yang merupakan 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 nya menerapkan kueri dan mutasi serta meneruskannya ke metode baca-tulis executeGraphql atau metode executeGraphqlRead hanya baca.
  • Antarmuka khusus untuk operasi data massal, yang bukan 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 dibuat berisi antarmuka dan fungsi yang sesuai dengan definisi gql, 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 tanpa batas 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 ditiru identitasnya (lihat bagian berikutnya), atau sebagai pengguna yang tidak diautentikasi yang ditiru identitasnya. Pengguna yang tidak diautentikasi hanya dapat menjalankan operasi yang ditandai sebagai PUBLIC.

Pada 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 klaim sub. (Nilai ini sama dengan nilai server auth.uid yang dapat Anda referensikan dalam SQL Connect GraphQL operations.)

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 dibuat 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, token autentikasi akan otomatis diverifikasi 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 Admin SDK's verifyIdToken metode untuk memvalidasi dan mendekode token autentikasi. Misalnya, endpoint Anda diimplementasikan sebagai fungsi HTTP biasa dan Anda telah meneruskan token Firebase Authentication ke endpoint Anda 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 tanpa batas

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 lengkap 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 satu kali yang belum Anda tentukan gql mutasi atau kueri, Anda dapat menggunakan metode executeGraphql atau metode hanya baca executeGraphqlRead.

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 ditiru identitasnya (lihat bagian berikutnya), atau sebagai pengguna yang tidak diautentikasi yang ditiru identitasnya. 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 menghormati 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 lengkap 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 menggunakan data massal. Dari argumen yang diberikan, setiap metode membuat dan menjalankan mutasi 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);

Catatan performa untuk operasi massal

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

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

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

Apa langkah selanjutnya?