Admin Database API 소개

Admin SDK를 사용하면 전체 관리자 권한이나 보다 세분화된 제한된 권한으로 실시간 데이터베이스 데이터를 읽고 쓸 수 있습니다. 이 문서에서는 Firebase Realtime Database 액세스를 위해 프로젝트에 Firebase Admin SDK를 추가하는 방법을 설명합니다.

Admin SDK 설정

서버에서 Firebase 실시간 데이터베이스를 시작하려면 우선 원하는 언어로 Firebase Admin SDK를 설정해야 합니다.

Admin SDK 인증

서버에서 Firebase Admin SDK를 사용하여 Firebase Realtime Database에 액세스하려면 먼저 Firebase로 서버를 인증해야 합니다. 서버 인증 시 클라이언트 앱처럼 사용자 계정의 사용자 인증 정보로 로그인하는 것이 아니라 서버를 Firebase에서 식별할 수 있도록 서비스 계정으로 인증합니다.

Firebase Admin SDK를 사용하여 인증할 때는 다음과 같이 2가지 수준의 액세스가 있습니다.

Firebase Admin SDK 인증 액세스 수준
관리자 권한 프로젝트의 Realtime Database 전체를 읽고 쓸 수 있습니다. 데이터 마이그레이션 또는 재구성과 같이 프로젝트의 리소스에 무제한으로 액세스해야 하는 관리 작업을 실행하는 데 사용되며 신중하게 사용해야 합니다.
제한된 권한 프로젝트의 Realtime Database에 대한 액세스 권한은 서버에 필요한 리소스로만 제한됩니다. 액세스 요구사항이 명확하게 정의된 관리 작업을 실행하는 데 사용됩니다. 예를 들어 전체 데이터베이스에서 데이터를 읽는 요약 작업을 실행할 때 읽기 전용 보안 규칙을 설정한 후 이 규칙으로 제한된 권한을 사용해 Admin SDK를 초기화하면 의도하지 않은 쓰기를 방지할 수 있습니다.

관리자 권한으로 인증

Firebase 프로젝트에서 편집자 역할을 갖는 서비스 계정의 인증 정보로 Firebase Admin SDK를 초기화하면 해당 인스턴스는 프로젝트의 Realtime Database 전체에 대해 읽기 및 쓰기 권한을 갖습니다.

자바
// Fetch the service account key JSON file contents
FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccount.json");

// Initialize the app with a service account, granting admin privileges
FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
    // The database URL depends on the location of the database
    .setDatabaseUrl("https://DATABASE_NAME.firebaseio.com")
    .build();
FirebaseApp.initializeApp(options);

// As an admin, the app has access to read and write all data, regardless of Security Rules
DatabaseReference ref = FirebaseDatabase.getInstance()
    .getReference("restricted_access/secret_document");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot dataSnapshot) {
    Object document = dataSnapshot.getValue();
    System.out.println(document);
  }

  @Override
  public void onCancelled(DatabaseError error) {
  }
});
Node.js
var admin = require("firebase-admin");

// Fetch the service account key JSON file contents
var serviceAccount = require("path/to/serviceAccountKey.json");

// Initialize the app with a service account, granting admin privileges
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  // The database URL depends on the location of the database
  databaseURL: "https://DATABASE_NAME.firebaseio.com"
});

// As an admin, the app has access to read and write all data, regardless of Security Rules
var db = admin.database();
var ref = db.ref("restricted_access/secret_document");
ref.once("value", function(snapshot) {
  console.log(snapshot.val());
});
Python
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Fetch the service account key JSON file contents
cred = credentials.Certificate('path/to/serviceAccountKey.json')

# Initialize the app with a service account, granting admin privileges
firebase_admin.initialize_app(cred, {
    'databaseURL': 'https://databaseName.firebaseio.com'
})

# As an admin, the app has access to read and write all data, regradless of Security Rules
ref = db.reference('restricted_access/secret_document')
print(ref.get())
Go
ctx := context.Background()
conf := &firebase.Config{
	DatabaseURL: "https://databaseName.firebaseio.com",
}
// Fetch the service account key JSON file contents
opt := option.WithCredentialsFile("path/to/serviceAccountKey.json")

// Initialize the app with a service account, granting admin privileges
app, err := firebase.NewApp(ctx, conf, opt)
if err != nil {
	log.Fatalln("Error initializing app:", err)
}

client, err := app.Database(ctx)
if err != nil {
	log.Fatalln("Error initializing database client:", err)
}

// As an admin, the app has access to read and write all data, regradless of Security Rules
ref := client.NewRef("restricted_access/secret_document")
var data map[string]interface{}
if err := ref.Get(ctx, &data); err != nil {
	log.Fatalln("Error reading from database:", err)
}
fmt.Println(data)

제한된 권한으로 인증

필요한 리소스에 대한 권한만 부여하는 것이 좋습니다. Firebase 앱 인스턴스가 액세스할 수 있는 리소스를 보다 세밀하게 제어하려면 보안 규칙에서 고유 식별자를 사용하여 서비스를 나타냅니다. 그런 다음 적절한 규칙을 설정하여 필요한 리소스에 대한 권한을 서비스에 부여합니다. 예를 들면 다음과 같습니다.

{
  "rules": {
    "public_resource": {
      ".read": true,
      ".write": true
    },
    "some_resource": {
      ".read": "auth.uid === 'my-service-worker'",
      ".write": false
    },
    "another_resource": {
      ".read": "auth.uid === 'my-service-worker'",
      ".write": "auth.uid === 'my-service-worker'"
    }
  }
}

그런 다음 서버에서 Firebase 앱을 초기화할 때 databaseAuthVariableOverride 옵션을 사용하여 데이터베이스 규칙에 사용되는 auth 객체를 재정의합니다. 이 커스텀 auth 객체의 uid 필드를 보안 규칙에서 서비스를 나타내는 데 사용한 식별자로 설정합니다.

자바
// Fetch the service account key JSON file contents
FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountCredentials.json");

// Initialize the app with a custom auth variable, limiting the server's access
Map<String, Object> auth = new HashMap<String, Object>();
auth.put("uid", "my-service-worker");

FirebaseOptions options = new FirebaseOptions.Builder()
    .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
    // The database URL depends on the location of the database
    .setDatabaseUrl("https://DATABASE_NAME.firebaseio.com")
    .setDatabaseAuthVariableOverride(auth)
    .build();
FirebaseApp.initializeApp(options);

// The app only has access as defined in the Security Rules
DatabaseReference ref = FirebaseDatabase
    .getInstance()
    .getReference("/some_resource");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        String res = dataSnapshot.getValue();
        System.out.println(res);
    }
});
Node.js
var admin = require("firebase-admin");

// Fetch the service account key JSON file contents
var serviceAccount = require("path/to/serviceAccountKey.json");

// Initialize the app with a custom auth variable, limiting the server's access
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  // The database URL depends on the location of the database
  databaseURL: "https://DATABASE_NAME.firebaseio.com",
  databaseAuthVariableOverride: {
    uid: "my-service-worker"
  }
});

// The app only has access as defined in the Security Rules
var db = admin.database();
var ref = db.ref("/some_resource");
ref.once("value", function(snapshot) {
  console.log(snapshot.val());
});
Python
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Fetch the service account key JSON file contents
cred = credentials.Certificate('path/to/serviceAccountKey.json')

# Initialize the app with a custom auth variable, limiting the server's access
firebase_admin.initialize_app(cred, {
    'databaseURL': 'https://databaseName.firebaseio.com',
    'databaseAuthVariableOverride': {
        'uid': 'my-service-worker'
    }
})

# The app only has access as defined in the Security Rules
ref = db.reference('/some_resource')
print(ref.get())
Go
ctx := context.Background()
// Initialize the app with a custom auth variable, limiting the server's access
ao := map[string]interface{}{"uid": "my-service-worker"}
conf := &firebase.Config{
	DatabaseURL:  "https://databaseName.firebaseio.com",
	AuthOverride: &ao,
}

// Fetch the service account key JSON file contents
opt := option.WithCredentialsFile("path/to/serviceAccountKey.json")

app, err := firebase.NewApp(ctx, conf, opt)
if err != nil {
	log.Fatalln("Error initializing app:", err)
}

client, err := app.Database(ctx)
if err != nil {
	log.Fatalln("Error initializing database client:", err)
}

// The app only has access as defined in the Security Rules
ref := client.NewRef("/some_resource")
var data map[string]interface{}
if err := ref.Get(ctx, &data); err != nil {
	log.Fatalln("Error reading from database:", err)
}
fmt.Println(data)

경우에 따라서는 Admin SDK의 범위를 줄여 미인증 클라이언트로 작동하게 할 수 있습니다. 이렇게 하려면 데이터베이스 auth 변수 재정의에 null 값을 제공합니다.

자바
// Fetch the service account key JSON file contents
FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountCredentials.json");

FirebaseOptions options = new FirebaseOptions.Builder()
    .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
    // The database URL depends on the location of the database
    .setDatabaseUrl("https://DATABASE_NAME.firebaseio.com")
    .setDatabaseAuthVariableOverride(null)
    .build();
FirebaseApp.initializeApp(options);

// The app only has access to public data as defined in the Security Rules
DatabaseReference ref = FirebaseDatabase
    .getInstance()
    .getReference("/public_resource");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        String res = dataSnapshot.getValue();
        System.out.println(res);
    }
});
Node.js
var admin = require("firebase-admin");

// Fetch the service account key JSON file contents
var serviceAccount = require("path/to/serviceAccountKey.json");

// Initialize the app with a null auth variable, limiting the server's access
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  // The database URL depends on the location of the database
  databaseURL: "https://DATABASE_NAME.firebaseio.com",
  databaseAuthVariableOverride: null
});

// The app only has access to public data as defined in the Security Rules
var db = admin.database();
var ref = db.ref("/public_resource");
ref.once("value", function(snapshot) {
  console.log(snapshot.val());
});
Python
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Fetch the service account key JSON file contents
cred = credentials.Certificate('path/to/serviceAccountKey.json')

# Initialize the app with a None auth variable, limiting the server's access
firebase_admin.initialize_app(cred, {
    'databaseURL': 'https://databaseName.firebaseio.com',
    'databaseAuthVariableOverride': None
})

# The app only has access to public data as defined in the Security Rules
ref = db.reference('/public_resource')
print(ref.get())
Go
ctx := context.Background()
// Initialize the app with a nil auth variable, limiting the server's access
var nilMap map[string]interface{}
conf := &firebase.Config{
	DatabaseURL:  "https://databaseName.firebaseio.com",
	AuthOverride: &nilMap,
}

// Fetch the service account key JSON file contents
opt := option.WithCredentialsFile("path/to/serviceAccountKey.json")

app, err := firebase.NewApp(ctx, conf, opt)
if err != nil {
	log.Fatalln("Error initializing app:", err)
}

client, err := app.Database(ctx)
if err != nil {
	log.Fatalln("Error initializing database client:", err)
}

// The app only has access to public data as defined in the Security Rules
ref := client.NewRef("/some_resource")
var data map[string]interface{}
if err := ref.Get(ctx, &data); err != nil {
	log.Fatalln("Error reading from database:", err)
}
fmt.Println(data)

다음 단계