Sử dụng SDK dành cho quản trị viên với tính năng Kết nối dữ liệu

Firebase Admin SDK là một tập hợp các thư viện máy chủ cho phép bạn tương tác với Firebase từ các môi trường có đặc quyền để thực hiện các thao tác như chạy truy vấn và thay đổi trên một Firebase Data Connect dịch vụ để quản lý dữ liệu hàng loạt và các thao tác khác có đặc quyền cấp cao và thông tin đăng nhập được nhập vai.

Admin SDK cung cấp cho bạn một API để gọi các thao tác ở cả chế độ đọc/ghi và chế độ chỉ có thể đọc. Với các thao tác chỉ đọc, bạn có thể yên tâm triển khai các hàm quản trị không thể sửa đổi dữ liệu trong cơ sở dữ liệu.

Thiết lập SDK dành cho quản trị viên

Để bắt đầu sử dụng với Firebase Data Connect trên máy chủ, trước tiên, bạn cần cài đặt và thiết lập Admin SDK cho Node.js.

Khởi chạy SDK dành cho quản trị viên trong tập lệnh

Để khởi chạy SDK, hãy nhập các tiện ích Data Connect và khai báo mã dịch vụ dự án cũng như vị trí.


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

Thiết kế truy vấn và thay đổi để sử dụng với Admin SDK

Admin SDK rất hữu ích để chạy các thao tác Data Connect, hãy cân nhắc những điều sau.

Tìm hiểu về SDK và chỉ thị thao tác @auth(level: NO_ACCESS)

Admin SDK hoạt động với các đặc quyền, nên SDK này có thể thực thi mọi truy vấn và thay đổi của bạn bất kể cấp truy cập được thiết lập bằng các @auth chỉ thị, bao gồm cả cấp NO_ACCESS.

Nếu cùng với các thao tác của ứng dụng, bạn sắp xếp các truy vấn và thay đổi quản trị trong các tệp nguồn .gql để nhập vào tập lệnh quản trị, thì Firebase khuyên bạn nên đánh dấu các thao tác quản trị mà không có cấp truy cập uỷ quyền nào hoặc có thể rõ ràng hơn và đặt các thao tác đó thành NO_ACCESS. Dù bằng cách nào, điều này cũng ngăn các thao tác như vậy được thực thi từ ứng dụng hoặc trong các bối cảnh không có đặc quyền khác.

Sử dụng SDK với trình mô phỏng Data Connect

Trong môi trường nguyên mẫu và thử nghiệm, bạn có thể hữu ích khi thực hiện việc gieo dữ liệu và các thao tác khác trên dữ liệu địa phương. Admin SDK giúp bạn đơn giản hoá quy trình làm việc vì có thể bỏ qua quá trình xác thực và uỷ quyền cho các luồng cục bộ. (Bạn cũng có thể chọn tham gia tuân thủ cấu hình xác thực và uỷ quyền của các thao tác bằng cách mạo danh người dùng.)

Firebase Admin SDK sẽ tự động kết nối với trình mô phỏng Data Connect khi biến môi trường DATA_CONNECT_EMULATOR_HOST được thiết lập:

export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"

Để biết thêm thông tin, hãy xem các bài viết sau:

Chạy các thao tác quản trị

Admin SDK được cung cấp cho các thao tác có đặc quyền trên dữ liệu quan trọng của bạn.

Admin SDK cung cấp 3 tập hợp API:

  • SDK quản trị được tạo, là các SDK an toàn về kiểu được tạo từ các định nghĩa gql theo cùng một cách mà bạn tạo SDK ứng dụng.
  • Một giao diện chung để chạy các thao tác GraphQL tuỳ ý, trong đó mã của bạn triển khai các truy vấn và thay đổi, đồng thời truyền các truy vấn và thay đổi đó đến phương thức đọc-ghi executeGraphql hoặc phương thức chỉ đọc executeGraphqlRead.
  • Một giao diện chuyên biệt cho các thao tác dữ liệu hàng loạt, thay vì các phương thức executeGraphql chung, sẽ hiển thị các phương thức dành riêng cho các thao tác thay đổi: insert, insertMany, upsertupsertMany.

Quản lý dữ liệu bằng các SDK được tạo

Bạn tạo SDK quản trị từ các định nghĩa gql theo cùng một cách mà bạn tạo SDK ứng dụng.

SDK quản trị được tạo chứa các giao diện và hàm tương ứng với các định nghĩa gql, mà bạn có thể dùng để thực hiện các thao tác trên cơ sở dữ liệu. Ví dụ: giả sử bạn đã tạo một SDK cho cơ sở dữ liệu bài hát, cùng với một truy vấn 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 } }
);

Hoặc để chỉ định cấu hình trình kết nối:

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

Nhập vai người dùng chưa xác thực

Admin SDK được dùng để chạy từ các môi trường đáng tin cậy và do đó có quyền truy cập không hạn chế vào cơ sở dữ liệu của bạn.

Khi chạy các thao tác công khai bằng SDK quản trị, bạn nên tránh chạy thao tác với đầy đủ đặc quyền quản trị viên (tuân theo nguyên tắc về đặc quyền tối thiểu). Thay vào đó, bạn nên chạy thao tác dưới dạng người dùng được nhập vai (xem phần tiếp theo) hoặc dưới dạng người dùng chưa xác thực được nhập vai. Người dùng chưa xác thực chỉ có thể chạy các thao tác được đánh dấu là PUBLIC.

Trong ví dụ trên, truy vấn getSongs được thực thi dưới dạng người dùng chưa xác thực.

Nhập vai người dùng

Bạn cũng có thể thực hiện các thao tác thay mặt cho những người dùng cụ thể bằng cách truyền một phần hoặc toàn bộ mã thông báo Firebase Authentication trong tuỳ chọn impersonate; tối thiểu, bạn phải chỉ định Mã nhận dạng người dùng của người dùng trong yêu cầu xác nhận sub. (Đây là cùng một giá trị với giá trị máy chủ auth.uid bạn có thể tham chiếu trong các thao tác GraphQL.)Data Connect

Khi bạn nhập vai người dùng, thao tác sẽ chỉ thành công nếu dữ liệu người dùng mà bạn cung cấp vượt qua các bước kiểm tra xác thực được chỉ định trong định nghĩa GraphQL.

Nếu bạn đang gọi SDK được tạo từ một điểm cuối có thể truy cập công khai, thì điều quan trọng là điểm cuối đó phải yêu cầu xác thực và bạn phải xác thực tính toàn vẹn của mã thông báo xác thực trước khi sử dụng mã thông báo đó để mạo danh người dùng.

Khi sử dụng có thể gọi Cloud Functions, mã thông báo xác thực sẽ tự động được xác minh và bạn có thể sử dụng mã thông báo đó như trong ví dụ sau:

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

    // ...
});

Nếu không, hãy sử dụng Admin SDK's verifyIdToken phương thức để xác thực và giải mã mã thông báo xác thực. Ví dụ: giả sử điểm cuối của bạn được triển khai dưới dạng một hàm HTTP thuần tuý và bạn đã truyền mã thông báo Firebase Authentication đến điểm cuối bằng tiêu đề authorization, như thường lệ:

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

    // ...
});

Chỉ khi thực hiện các tác vụ quản trị thực sự, chẳng hạn như di chuyển dữ liệu, từ một môi trường an toàn, không thể truy cập công khai, bạn mới nên chỉ định một mã nhận dạng người dùng không bắt nguồn từ một nguồn có thể xác minh:

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

Chạy với quyền truy cập không hạn chế

Nếu bạn đang thực hiện một thao tác yêu cầu quyền cấp quản trị, hãy bỏ qua tham số nhập vai khỏi lệnh gọi:

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

Một thao tác được gọi theo cách này có quyền truy cập hoàn toàn vào cơ sở dữ liệu. Nếu bạn có các truy vấn hoặc thay đổi chỉ dùng cho mục đích quản trị, thì bạn nên xác định các truy vấn hoặc thay đổi đó bằng chỉ thị @auth(level: NO_ACCESS). Việc này đảm bảo rằng chỉ những người gọi cấp quản trị mới có thể thực thi các thao tác này.

Quản lý dữ liệu bằng các phương thức executeGraphql

Nếu cần thực thi các thao tác một lần mà bạn chưa xác định gql các thay đổi hoặc truy vấn, bạn có thể sử dụng phương thức executeGraphql hoặc phương thức chỉ đọc executeGraphqlRead.

Nhập vai người dùng chưa xác thực

Khi chạy các thao tác công khai bằng SDK quản trị, bạn nên tránh chạy thao tác với đầy đủ đặc quyền quản trị viên (tuân theo nguyên tắc về đặc quyền tối thiểu). Thay vào đó, bạn nên chạy thao tác dưới dạng người dùng được nhập vai (xem phần tiếp theo) hoặc dưới dạng người dùng chưa xác thực được nhập vai. Người dùng chưa xác thực chỉ có thể chạy các thao tác được đánh dấu là 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);

Nhập vai người dùng

Ngoài ra, có những trường hợp sử dụng mà bạn muốn tập lệnh sửa đổi dữ liệu người dùng dựa trên thông tin đăng nhập bị hạn chế, thay mặt cho một người dùng cụ thể. Phương pháp này tuân theo nguyên tắc về đặc quyền tối thiểu.

Để sử dụng giao diện này, hãy thu thập thông tin từ mã thông báo xác thực JWT tuỳ chỉnh tuân theo định dạng mã thông báo Authentication. Hãy xem thêm hướng dẫn về mã thông báo tuỳ chỉnh.

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

Sử dụng thông tin đăng nhập quản trị

Nếu bạn đang thực hiện một thao tác yêu cầu quyền cấp quản trị, hãy bỏ qua tham số nhập vai khỏi lệnh gọi:

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

Một thao tác được gọi theo cách này có quyền truy cập hoàn toàn vào cơ sở dữ liệu. Nếu bạn có các truy vấn hoặc thay đổi chỉ dùng cho mục đích quản trị, thì bạn nên xác định các truy vấn hoặc thay đổi đó bằng chỉ thị @auth(level: NO_ACCESS). Việc này đảm bảo rằng chỉ những người gọi cấp quản trị mới có thể thực thi các thao tác này.

Thực hiện các thao tác dữ liệu hàng loạt

Firebase khuyên bạn nên sử dụng Admin SDK cho các thao tác dữ liệu hàng loạt trên cơ sở dữ liệu phát hành công khai.

SDK cung cấp các phương thức sau để xử lý dữ liệu hàng loạt. Từ các đối số được cung cấp, mỗi phương thức sẽ tạo và thực thi một thay đổi 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);

Lưu ý về hiệu suất cho các thao tác hàng loạt

Mỗi yêu cầu gửi đến phần phụ trợ sẽ phát sinh một chuyến khứ hồi đến Cloud SQL, vì vậy, bạn càng tạo lô nhiều thì thông lượng càng cao.

Tuy nhiên, kích thước lô càng lớn thì câu lệnh SQL được tạo càng dài. Khi đạt đến giới hạn độ dài câu lệnh SQL PostgreSQL, bạn sẽ gặp lỗi.

Trong thực tế, hãy thử nghiệm để tìm kích thước lô phù hợp cho khối lượng công việc của bạn.

Tiếp theo là gì?