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는 권한으로 작동하므로 NO_ACCESS 수준을 포함하여 @auth 지시문을 사용하여 설정된 액세스 수준에 관계없이 모든 쿼리와 변형을 실행할 수 있습니다.
클라이언트 작업과 함께 관리 스크립트로 가져오기 위해 .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"
자세한 내용은 다음을 참고하세요.
관리 작업 실행
Admin SDK은 중요한 데이터에 대한 권한 있는 작업을 위해 제공됩니다.
Admin SDK는 세 가지 API 집합을 제공합니다.
- 생성된 Admin SDK: 클라이언트 SDK를 생성하는 것과 동일한 방식으로
gql정의에서 생성된 유형 안전 SDK입니다. - 임의의 GraphQL 작업을 실행하기 위한 일반 인터페이스로, 코드가 쿼리와 변형을 구현하고 이를 읽기-쓰기
executeGraphql메서드 또는 읽기 전용executeGraphqlRead메서드에 전달합니다. - 일괄 데이터 작업을 위한 특수 인터페이스로, 일반
executeGraphql메서드 대신 변형 작업 전용 메서드인insert,insertMany,upsert,upsertMany를 노출합니다.
생성된 SDK로 데이터 관리
클라이언트 SDK를 생성하는 것과 동일한 방식으로 gql 정의에서 Admin 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 쿼리는 인증되지 않은 사용자로 실행됩니다.
사용자 가장
impersonate 옵션에서 Firebase Authentication 토큰의 일부 또는 전부를 전달하여 특정 사용자를 대신해 작업을 수행할 수도 있습니다. 최소한 하위 클레임에 사용자의 사용자 ID를 지정해야 합니다. (SQL Connect GraphQL 작업에서 참조할 수 있는 auth.uid 서버 값과 동일한 값입니다.)
사용자를 가장하는 경우 제공한 사용자 데이터가 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 } }
);
무제한 액세스로 실행
관리자 수준 권한이 필요한 작업을 수행하는 경우 호출에서 가장 매개변수를 생략합니다.
await upsertSong(adminDc, {
title: songTitle_one,
instrumentsUsed: [Instrument.VOCAL],
});
이 방식으로 호출된 작업은 데이터베이스에 대한 전체 액세스 권한을 가집니다. 관리 목적으로만 사용되는 쿼리나 변형이 있는 경우 @auth(level: NO_ACCESS) 지시어로 정의해야 합니다. 이렇게 하면 관리자 수준 호출자만 이러한 작업을 실행할 수 있습니다.
executeGraphql 메서드로 데이터 관리
gql 변형 또는 쿼리를 정의하지 않은 일회성 작업을 실행해야 하는 경우 executeGraphql 메서드 또는 읽기 전용 executeGraphqlRead 메서드를 사용할 수 있습니다.
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);
사용자 가장
또한 스크립트가 특정 사용자를 대신하여 제한된 사용자 인증 정보를 기반으로 사용자 데이터를 수정하도록 하려는 사용 사례도 있습니다. 이 접근 방식은 최소 권한의 원칙을 따릅니다.
이 인터페이스를 사용하려면 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" } } }
관리 사용자 인증 정보 사용
관리자 수준 권한이 필요한 작업을 수행하는 경우 호출에서 가장 매개변수를 생략합니다.
// 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);
중첩 관계형 작업(일대다 및 일대일)
Admin SDK는 일괄 작업에서 관계형 데이터를 지원합니다. 커스텀 변형과 마찬가지로 일대다 관계에는 객체 배열을 사용하고 일대일 관계에는 단일 객체를 사용합니다.
// 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);
일괄 작업 성능 참고사항
백엔드에 대한 각 요청은 Cloud SQL에 대한 왕복을 한 번 발생시키므로 일괄 처리할수록 처리량이 높아집니다.
하지만 배치 크기가 클수록 생성되는 SQL 문이 길어집니다. PostgreSQL SQL 문 길이 한도에 도달하면 오류가 발생합니다.
실제로 워크로드에 적합한 배치 크기를 찾기 위해 실험을 진행합니다.
다음 단계
- 자세히 알아보세요 데이터베이스에 데이터를 시드하는 방법Admin SDK
- 검토 APIAdmin SDK.
- 스키마 및 커넥터 관리, 서비스 및 데이터베이스 관리와 같은 다른 프로젝트 관리 작업에는 Firebase CLI 및 Google Cloud 콘솔을 사용합니다.