Node.js中的Firebase管理SDK全局应用程序初始化

iovurdzv  于 2023-03-19  发布在  Node.js
关注(0)|答案(4)|浏览(140)

我正在构建一个Express.js应用程序,使用Firebase Admin SDK实现ID令牌验证和Cloud Firestore访问等功能。在主app.js文件中,我将应用程序初始化为:

const admin = require('firebase-admin')

const serviceAccount = require('../config/account-credentials.json')
admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: 'https://databaseurl.firebaseio.com'
})

在另一个文件中,我所做的就是导入:

const admin = require('firebase-admin')

我可以调用admin.auth().verifyIdToken并很好地验证ID令牌。但是当我调用app.database()时,它抱怨应用程序从未初始化。再次初始化应用程序会创建一个新的错误,内容如下:
默认的Firebase应用程序已经存在。这意味着您多次调用initializeApp(),但没有提供应用程序名称作为第二个参数。大多数情况下,您只需调用initializeApp()一次。但如果您确实希望初始化多个应用程序,请向initializeApp()传递第二个参数,以便为每个应用程序提供唯一的名称。
我是否需要创建多个名称不同的应用程序才能正常工作?或者我如何在整个项目中使用一个应用程序。

smtd7mpg

smtd7mpg1#

您应该只初始化应用程序一次,然后重用该引用。有多种方法可以做到这一点,但我更喜欢导入firebase.ts(初始化Firebase应用程序和服务)到我的index.ts(或者任何你的入口点)。然后我传递一个引用到任何其他需要特定服务的文件。我使用TypeScript,所以如果你使用的是vanilla JS,可以根据需要进行调整。
firebase.ts

import * as admin from 'firebase-admin';

// Initialize our project application
admin.initializeApp();

// Set up database connection
const firestoreDb: FirebaseFirestore.Firestore = admin.firestore();
firestoreDb.settings({ timestampsInSnapshots: true });
export const db = firestoreDb;

我的索引.ts文件将导入它:

import { db } from './firebase';

然后,当我用Express设置我的路线时,我会将每条路线放在另一个文件中,每个文件都有自己的函数,然后将db引用传递给任何需要它的人。

app
    .route('events')
    .get((req: Request, res: Response) => {
      get_events(db, res);
      return;
    });

下面是一篇博客文章,我对此做了更多的解释:
https://medium.com/@jasonbyrne/how-to-structure-a-serverless-rest-api-with-firebase-functions-express-1d7b93aaa6af
如果你不喜欢依赖注入方法或者只喜欢延迟加载你需要的服务,你可以用另一种方法。在这种方法中,你可以把你的firebase.js文件(或者随便你怎么称呼它)导入到任何需要它的页面,然后调用一个函数来加载那个服务。这里我只是在做Firestore,但是你可以创建类似的函数来引用其他服务。
刚打出来作为样本...

import * as admin from 'firebase-admin';

// Initialize our project application
admin.initializeApp();

// Database reference, not yet loaded
let db: FirebaseFirestore.Firestore | null = null;

// Get cached db reference or create it
export function getDatabaseReference() {
    if (db === null) {
        db = admin.firestore();
    }
    return db;
}

希望能有所帮助。有什么问题尽管问我。

dgjrabp2

dgjrabp22#

我使用global在cloudRun中的一个微服务API中很好地实现了这一点。

const admin = require('firebase-admin');
global.GeoFirestore = require('geofirestore').GeoFirestore;

admin.initializeApp({
  credential: admin.credential.applicationDefault()
});

global.db = admin.firestore();
global.admin = admin;

在另一个模块中,我可以访问集合:

var docRef = db.collection("collection").doc(doc.id);
    docRef.update({state}).then((doc) => {
        console.log(doc)
    }).catch((error) => {
        console.log("Error getting document:", error);
    });

对于在GeoFirestore GeoPoint上工作,我需要全局管理:

const geofirestore = new GeoFirestore(db);
const geocollection = geofirestore.collection('bin');
var objectToBeStored = {
   ...data,
   coordinates: new admin.firestore.GeoPoint(coordinates.lat, coordinates.lng)
}
geocollection.add(objectToBeStored ).then((docRef) => {
    console.log(`added data: ${docRef.id}`);
}).catch((error) => {
    console.log(`error: ${error}`);
})
lqfhib0f

lqfhib0f3#

我是这么做的:我创建了一个 Package 器来 Package 我需要的admin.firestore()等函数,然后导入它并在所有其他函数中使用它:

函数共享.ts

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

admin.initializeApp(functions.config().firebase);

export const FunctionsShared = {
  firestore: () => admin.firestore()
};

我的 Firebase 函数.ts

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import {FunctionsShared} from './FunctionsShared';

export getStaleDocumentsQuery = functions.https.onCall(() => {
  // Use FunctionsShared.firestore() instead of admin.firestore()
  return FunctionsShared.firestore()
    .collection('mirror')
    .where('updated', '<', oneMonthAgo)
    .orderBy('updated')
    .limit(limit);
}
zkure5ic

zkure5ic4#

以下是在任何node.js服务器中初始化模块化firebase管理SDK的完整类型脚本代码:

import { credential } from "firebase-admin";
import { initializeApp, getApps, getApp } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";
import {
  FIREBASE_CLIENT_EMAIL,
  NEXT_PUBLIC_FIREBASE_DATABASE_URL,
  NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  FIREBASE_PRIVATE_KEY,
} from "../common/envVar";

const adminCredentials = {
  credential: credential.cert({
    projectId: NEXT_PUBLIC_FIREBASE_PROJECT_ID,
    clientEmail: FIREBASE_CLIENT_EMAIL,
    privateKey: JSON.parse(FIREBASE_PRIVATE_KEY),
  }),
  databaseURL: NEXT_PUBLIC_FIREBASE_DATABASE_URL,
};

// avoid initializing twice
const firebaseAdminApp =
  getApps().length === 0 ? initializeApp(adminCredentials) : getApp();

export const authAdmin = getAuth(firebaseAdminApp);

下面是如何使用它:

import { authAdmin } from "../server/initFirebaseAdmin";
const uid = (await authAdmin.verifyIdToken(token)).uid;

相关问题