Firebase Admin SDK は、特権環境から Firebase を操作するために使用するサーバー ライブラリのセットであり、Firebase SQL Connect サービスに対するクエリとミューテーションの実行、一括データ管理、権限昇格と権限借用された認証情報を使用したその他のオペレーションなどの操作を行うことができます。
Admin SDK には、 読み取り/書き込みモードと読み取り専用モードの両方でオペレーションを呼び出す API が用意されています。読み取り専用オペレーションを使用すると、データベース内のデータを変更できない管理機能を安心して実装できます。
Admin SDK の設定
サーバーで Firebase SQL Connect を使用して を使い始めるには、まず Node.js 用の Admin SDK をインストールして設定する必要があります。
スクリプトで Admin SDK を初期化する
SDK を初期化するには、SQL Connect 拡張機能をインポートし、 プロジェクトのサービス ID とロケーションを宣言します。
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 ソースファイルに整理する場合は、承認アクセスレベルのない管理オペレーションにマークを付けるか、NO_ACCESS として明示的に設定することをおすすめします。いずれにしても、これにより、クライアントやその他の特権のないコンテキストからこのようなオペレーションが実行されるのを防ぐことができます。
SQL Connect エミュレータで SDK を使用する
プロトタイプ環境とテスト環境では、ローカルデータに対してデータ シーディングなどのオペレーションを実行すると便利な場合があります。Admin SDK を使用すると、ローカル フローの認証と認可を無視できるため、ワークフローを簡素化できます。 (別のユーザーに成り代わることで、オペレーションの認証と認可の構成に明示的に準拠することもできます)。
環境変数 DATA_CONNECT_EMULATOR_HOST が設定されている場合、Firebase Admin SDK は SQL Connect
エミュレータに自動的に接続します。
export DATA_CONNECT_EMULATOR_HOST="127.0.0.1:9399"
詳しくは以下をご覧ください。
- ローカル開発でのデータ シーディングのガイド
- SQL Connect エミュレータのドキュメント。
管理オペレーションを実行する
Admin SDK は、重要なデータに対する特権オペレーション用に提供されています。
Admin SDK には、次の 3 つの API セットが用意されています。
- 生成された Admin SDK。クライアント SDK を生成するのと同じ方法で、
gql定義から生成されるタイプセーフな SDK です。 - 任意の GraphQL オペレーションを実行するための一般的なインターフェース。コードでクエリとミューテーションを実装し、読み取り / 書き込みの
executeGraphqlメソッドまたは読み取り専用のexecuteGraphqlReadメソッドに渡します。 - 一括データ オペレーション用の特別なインターフェース。
汎用的な
executeGraphqlメソッドではなく、 ミューテーション オペレーション専用のメソッド(insert、insertMany、upsert、upsertMany)を公開します。
生成された SDK でデータを管理する
クライアント SDK を生成するのと同じ方法で、Admin SDK
をgql定義から生成します。
生成された 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 クエリは認証されていないユーザーとして実行されます。
ユーザーの権限借用
`impersonate` オプションで `Firebase Authentication` トークンの一部または
すべてを渡すことで、特定のユーザーに代わってオペレーションを実行することもできます。少なくとも、サブクレームでユーザーのユーザー ID を指定する必要があります。(これは、
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 } }
);
// ...
});
それ以外の場合は、Admin SDK の verifyIdToken メソッドを使用して認証トークンを検証してデコードします
。たとえば、エンドポイントが
プレーン HTTP 関数として実装され、標準どおり authorization ヘッダーを使用して Firebase Authentication トークン
をエンドポイントに渡したとします。
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 } }
);
// ...
});
安全で公開アクセスできない環境からデータ移行などの真の管理タスクを実行する場合にのみ、検証可能なソースから生成されていないユーザー ID を指定する必要があります。
// Never do this if end users can initiate execution of the code!
const favoriteSongs = await getMyFavoriteSongs(
undefined,
{ impersonate: { authClaims } }
);
無制限のアクセス権で実行する
管理者レベルの権限を必要とするオペレーションを実行する場合は、呼び出しから impersonate パラメータを省略します。
await upsertSong(adminDc, {
title: songTitle_one,
instrumentsUsed: [Instrument.VOCAL],
});
この方法で呼び出されたオペレーションは、データベースに完全にアクセスできます。管理目的でのみ使用するクエリまたはミューテーションがある場合は、@auth(level: NO_ACCESS) ディレクティブを使用して定義する必要があります。これにより、管理者レベルの呼び出し元のみがこれらのオペレーションを実行できるようになります。
executeGraphql メソッドでデータを管理する
gql
ミューテーションまたはクエリを定義していない 1 回限りのオペレーションを実行する必要がある場合は、executeGraphql メソッドまたは読み取り専用の
executeGraphqlRead メソッドを使用できます。
executeGraphql を使用してカスタムのネストされたリレーショナル オペレーション(1 対多)を実行する
特権環境で Admin SDK からオペレーションを呼び出す場合、標準のフラット(ネストされていない)挿入(個々の Movie レコードや Actor レコードの挿入など)では、変数に @allow ディレクティブを指定する必要はありません。
ただし、ネストされたリレーショナル挿入(最初のレビューとともに映画を挿入するなど)の場合は、コンパイルされた変数スキーマ内のネストされたリレーショナル フィールドを静的に許可するために、変数定義で @allow ディレクティブを宣言する必要があります。
// Custom GraphQL mutation with nested relational insert
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 });
認証されていないユーザーの権限借用
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);
ユーザーの権限借用
特定のユーザーに代わって、制限付きの認証情報に基づいてスクリプトでユーザーデータを変更する場合もあります。このアプローチは、最小権限の原則に沿ったものです。
このインターフェースを使用するには、 Authenticationトークン形式に準拠したカスタマイズされた JWT 認証トークンから情報を収集します。 カスタム トークンのガイドもご覧ください。
// 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" } } }
管理者の認証情報を使用する
管理者レベルの権限を必要とするオペレーションを実行する場合は、呼び出しから impersonate パラメータを省略します。
// 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 には、一括データを操作するための次のメソッドが用意されています。指定された引数から、各メソッドは 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 対多)
Admin SDK は、一括オペレーションでリレーショナル データをサポートしています。
// Example of inserting a movie with nested reviews
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);
一括オペレーションのパフォーマンスに関する注意事項
バックエンドへのリクエストごとに Cloud SQL への往復が 1 回発生するため、バッチ処理を行うほどスループットが高くなります。
ただし、バッチサイズが大きいほど、生成される SQL ステートメントが長くなります。PostgreSQL SQL ステートメントの長さ制限に達すると、エラーが発生します。
実際には、ワークロードに適したバッチサイズを見つけるために試行錯誤してください。
次のステップ
- を使用してデータベースにデータをシードする方法を確認するAdmin SDK
- の API を確認する。Admin SDK
- Firebase CLI と Google Cloud コンソールを使用して、その他のプロジェクト 管理オペレーション(スキーマとコネクタの管理、サービスとデータベースの管理など)を行う。