Node.js - Firebase服务帐户私钥无法解析

63
我在app.js文件中使用.env变量来访问密钥。一切都正常工作,直到我下载了一个新的Firebase服务帐户私钥。当我用新值替换旧值后,由于在终端上运行node app.js时不断出现错误消息,我无法再访问该密钥:
/Users/Cpu/Desktop/...../node_modules/firebase-admin/lib/auth/credential.js:129 throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_CREDENTIAL, 'Failed to parse private key: ' + error); ^ Error: Failed to parse private key: Error: Invalid PEM formatted message. at FirebaseAppError.FirebaseError [as constructor] (/Users/Cpu/Desktop/...../node_modules/firebase-admin/lib/utils/error.js:39:28) at FirebaseAppError.PrefixedFirebaseError [as constructor] (/Users/Cpu/Desktop/...../node_modules/firebase-admin/lib/utils/error.js:85:28) at new FirebaseAppError (/Users/Cpu/Desktop/...../node_modules/firebase-admin/lib/utils/error.js:119:28) at new Certificate (/Users/Cpu/Desktop/...../node_modules/firebase-admin/lib/auth/credential.js:129:19) at new CertCredential (/Users/Cpu/Desktop/...../node_modules/firebase-admin/lib/auth/credential.js:192:64) at Object.cert (/Users/Cpu/Desktop/.....) at Object. (/Users/Cpu/Desktop/...../app.js:14:32) at Module._compile (module.js:571:32) at Object.Module._extensions..js (module.js:580:10) at Module.load (module.js:488:32) at FirebaseAppError.FirebaseError [as constructor] npm ERR! code ELIFECYCLE npm ERR! errno 1
我所做的就是复制和粘贴新的私钥,然后添加并保存.env文件,推送到heroku,但它不再起作用。我甚至下载了一个新的私钥,但仍出现相同的问题。
旧的和新的私钥
// old Private Key
-----BEGIN PRIVATE KEY-----\nbbbbbbbb\n-----END PRIVATE KEY-----\n

// new Private Key
-----BEGIN PRIVATE KEY-----\nzzzzzzzz\n-----END PRIVATE KEY-----\n

.env 文件:

FIREBASE_PROJECT_ID=wwwwwwww
FIREBASE_CLIENT_EMAIL=xxxxxxxx
FIREBASE_DATABASE_URL=yyyyyyyy
FIREBASE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\nzzzzzzzz\n-----END PRIVATE KEY-----\n

app.js 文件:

const dotenv = require('dotenv');
dotenv.load();

var admin = require("firebase-admin");
admin.initializeApp({
  credential: admin.credential.cert({
      projectId: process.env.FIREBASE_PROJECT_ID,   // I get no error here
      clientEmail: process.env.FIREBASE_CLIENT_EMAIL,   // I get no error here
      privateKey: process.env.FIREBASE_PRIVATE_KEY   // I get error HERE
  }),
  databaseURL: process.env.FIREBASE_DATABASE_URL
});

我该如何解决这个问题?

6个回答

195

问题是因为我在.env文件中使用了dotenv变量,导致FIREBASE_PRIVATE_KEY内部有转义字符:\n

我不得不遵循这个答案并在末尾添加.replace(/\\n/g, '\n')来解析它:

privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n')

现在代码看起来像这样:

admin.initializeApp({
  credential: admin.credential.cert({
      projectId: process.env.FIREBASE_PROJECT_ID, // I get no error here
      clientEmail: process.env.FIREBASE_CLIENT_EMAIL, // I get no error here
      privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n') // NOW THIS WORKS!!!
  }),
  databaseURL: process.env.FIREBASE_DATABASE_URL
});

1
在创建 Firebase 新密钥后,我遇到了这个问题。我将密钥值保存在 Firebase 环境变量中,因此不需要调整 \n。当我执行 firebase deploy --only functions 时,出现了 PEM 错误。有什么建议吗? - Chadd
我以前从未使用过Firebase环境变量。但愿我能帮忙。 - Lance Samaria
这解决了我的问题。奇怪的是,它在没有它的情况下工作,然后突然停止工作。无论如何,我投票支持让其他人看到。 - Patrick Michaelsen
谢谢!使用 Firebase 配置变量完美运行。例如,访问 functions.config().var.name.replace(/\n/g, '\n')(通过 firebase functions:config:set var.name="xxx" 设置)。 - The Geek
3
我在AWS弹性Beanstalk上遇到了相同的情况,我在环境变量中添加了\\n而不是\n,并在访问它们的地方添加了替换。 - Abishek Kumar
显示剩余6条评论

39

根据 dotenv 文档,你必须使用双引号将密钥括起来以启用扩展的换行选项。

你可以在 dotenv 的 Github 页面的规则部分检查该选项。

https://github.com/motdotla/dotenv#rules

  FIREBASE_PROJECT_ID=wwwwwwww
  FIREBASE_CLIENT_EMAIL=xxxxxxxx
  FIREBASE_DATABASE_URL=yyyyyyyy
  FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nzzzzzzzz\n-----END PRIVATE KEY-----\n"

2

更新:2022年

如果有人仍在寻找以下配置的解决方案,这是我解决它的方法。

技术栈:

TypeScript Express Dotenv Heroku

将整个JSON文件转换为Base64格式

使用此链接进行转换:Base64编码器 或您也可以使用其他工具。

将编码后的字符串添加到您的.env文件中。

FIREBASE_API_KEY=<your_large_base64_string>

接下来是firebase-init.ts的代码,用于使用密钥。
import * as admin from 'firebase-admin';

declare var process: {
    env: {
        FIREBASE_KEYS: string;
    }
}
const initializeFirebaseAdmin = (isProd = true) => {
    const firebase_private_key_b64 = Buffer.from(process.env.FIREBASE_KEYS, 'base64');
    const firebase_private_key = firebase_private_key_b64.toString('utf8');
    admin.initializeApp({
        credential: admin.credential.cert(JSON.parse(firebase_private_key))
    });
}


export { initializeFirebaseAdmin }

为了保护您的应用程序安全,请勿与不受信任的第三方共享您的私钥。此外,无需像以前的答案所示那样转换为/从base 64。 - warfield

0
对我来说,我只是将整个服务帐户放在我的.env文件中,就像这样:

.env

FIREBASE_ADMIN_API={"type":..."private_key":"..."...}

然后我这样导入它:

server.ts

const firebase_admin_config = JSON.parse(process.env.FIREBASE_ADMIN_API);

getApps().length === 0 ? initializeApp({
  credential: credential.cert(firebase_admin_config)
}) : getApp();

0

我相信 cert 函数正在等待 JSON 对象,尝试将键转换为 JSON,我认为它会起作用。

credential: admin.credential.cert(JSON.parse(serviceAccountKey))

这对我有用!


2
它显示SyntaxError:JSON中的位置1处有意外的令牌o。 - Piyush Pandey
1
@PiyushPandey 我也遇到了同样的问题。我正在使用dotenv,而且我在使用它的文件之后才要求dotenv,所以这对我有用。可能没有什么帮助,但只是让你知道这就是我的解决方法! - Akash Kundu

-3

Firebase下生成管理SDK Firebase:设置 > 管理SDK Firebase。进入您的项目中的Google Cloud平台,点击IAM管理员 > 源帐户,并在帐户服务中生成密钥代码(您的帐户服务在管理SDK Firebase中生成)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接