将带有服务帐户的Firebase应用程序部署到Heroku(使用dotenv的环境变量)

时间:2016-12-22 15:58:05

标签: node.js heroku firebase environment-variables firebase-authentication

我有一个使用firebase服务帐户的节点应用程序。我想将应用程序部署到Heroku,但我不想公开我的秘密密钥。我直接从公共github仓库部署,所以我不想在部署中包含服务帐户文件。

我可以使用服务帐户json文件,使每个属性成为环境变量,将每个变量添加到Heroku并进行部署。一切都很好(在我的firebase应用程序上授权新的Heroku域之后),但是有更好的方法吗?这是有效的,但这样做很麻烦(复制和粘贴每个变量并移动它)。我错过了一种更简单的方法吗?

这是我正在做的改变。从这行从文件中提取凭据:

admin.initializeApp({
  credential: admin.credential.cert('./path/firebase-service-account.json'),
  databaseURL: "https://my-firebase-app.firebaseio.com"
});

对于从环境变量引入所有相同内容的对象:

admin.initializeApp({
  credential: admin.credential.cert({
    "type": process.env.FIREBASE_TYPE,
    "project_id": process.env.FIREBASE_PROJECT_ID,
    "private_key_id": process.env.FIREBASE_PRIVATE_KEY_ID,
    "private_key": process.env.FIREBASE_PRIVATE_KEY,
    "client_email": process.env.FIREBASE_CLIENT_EMAIL,
    "client_id": process.env.FIREBASE_CLIENT_ID,
    "auth_uri": process.env.FIREBASE_AUTH_URI,
    "token_uri": process.env.FIREBASE_TOKEN_URI,
    "auth_provider_x509_cert_url": process.env.FIREBASE_AUTH_PROVIDER_X509_CERT_URL,
    "client_x509_cert_url": process.env.FIREBASE_CLIENT_X509_CERT_URL
  }),
  databaseURL: "https://my-firebase-app.firebaseio.com"
});

这是将带有服务帐户的firebase应用程序部署到Heroku的最佳做法吗?我正在使用dotenv节点模块来完成此任务。

5 个答案:

答案 0 :(得分:28)

证书选项对象有两个必填字段:clientEmailprivateKey。您的示例可以缩减为:

admin.initializeApp({
  credential: admin.credential.cert({
    "private_key": process.env.FIREBASE_PRIVATE_KEY,
    "client_email": process.env.FIREBASE_CLIENT_EMAIL,
  }),
  databaseURL: "https://my-firebase-app.firebaseio.com"
});

顺便说一下,某些环境可能会遇到private_key env var中的换行问题;我发现key.replace(/\\n/g, '\n')是一个简单的解决方案。

答案 1 :(得分:6)

  1. 将firebase配置JSON(serviceAccountKey)转换为base64编码的字符串,这可以通过多种方式来完成,例如使用openssl命令openssl base64 -in <firebaseConfig.json> -out <firebaseConfigBase64.txt>或使用如下所示的Node.js
Buffer.from(JSON.stringify({
  "type": "",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": ""
})).toString('base64')
  1. 将上述步骤的输出base64编码的字符串保存在GOOGLE_CONFIG_BASE64这样的env变量中。 (如果是Heroku,请将其保存到ConfigVars
  2. 在您的节点应用程序中初始化firebaseSdk
const firebaseAdminSdk = require('firebase-admin'),
    firebaseAdminApp = firebaseAdminSdk.initializeApp({credential: firebaseAdminSdk.credential.cert(
      JSON.parse(Buffer.from(process.env.GOOGLE_CONFIG_BASE64, 'base64').toString('ascii')))
});

答案 2 :(得分:3)

这是一种与我个人在将应用部署到使用 firebase 服务帐户的 heroku 时更喜欢使用的最佳答案略有不同的方法。

  • 按以下格式初始化您的 Firebase 应用程序:
const admin = require("firebase-admin");
require("dotenv").config();

const serviceAccount = JSON.parse(process.env.GOOGLE_CREDS);
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});
  • 将服务帐户密钥文件中的内容复制为 JSON,并将 GOOGLE_CREDS 设置为在您的 .env 中采用此值。确保默认删除 JSON 中的所有换行符,因为 .env 会将其作为字符串读取。 下面是它的外观示例: .env sample

  • 以相同的格式复制相同的键值并将其粘贴到您的 heroku 配置变量中。

希望对您有所帮助,谢谢。

答案 3 :(得分:1)

我刚刚使用了 Diokas 解决方案,并进行了以下改进: .env 只是:

注意对于 admin sdk 需要完整的配置文件....

FIREBASE_CREDS={"type","projectId","private_key","client_email"}
FIREBASE_DATABASE_URL=...

然后

var admin = require('firebase-admin');
require('dotenv').config();

const serviceAccount = JSON.parse(process.env.FIREBASE_CREDS);

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: process.env.FIREBASE_DATABASE_URL,
});
var db = admin.database();
module.exports = db;

答案 4 :(得分:0)

FWIW 我和@Huzaifa 做了同样的事情,除了没有对 JSON 字符串进行 base64 编码,到目前为止它对我来说很好:

const firebaseAdminSdk = require('firebase-admin');

// login and return a ref to the root of the firebase
function loginToFirebase() {
    // JSON stored in this env variable must come from Firebase Admin SDK service account's private key:
    // https://console.firebase.google.com/u/0/project/<your firebase>/settings/serviceaccounts/adminsdk
    const googleAuthJson = process.env.GOOGLE_AUTH_JSON;
    if (!googleAuthJson) throw new Error('The $GOOGLE_AUTH_JSON environment variable was not found!');

    return firebaseAdminSdk.initializeApp({
        credential: firebaseAdminSdk.credential.cert(JSON.parse(googleAuthJson)),
        databaseURL: "https://<your firebase>.firebaseio.com"
    }).database();
}