Firebase Cloud Functions Firestore触发器产生:错误:7 PERMISSION_DENIED:权限不足或不足

时间:2018-08-14 22:18:32

标签: typescript firebase google-cloud-firestore google-cloud-functions

当我的一个文档已使用触发器更新时,我正在尝试使用Firebase Cloud Function更新Firestore数据库中的文档。触发器被调用且工作正常,但是当我使用firebase admin实例获取要更新的其他文档时,出现以下错误。

Error: 7 PERMISSION_DENIED: Missing or insufficient permissions.
    at Object.exports.createStatusError (/user_code/node_modules/firebase-admin/node_modules/grpc/src/common.js:87:15)
    at ClientReadableStream._emitStatusIfDone (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client.js:235:26)
    at ClientReadableStream._receiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client.js:213:8)
    at Object.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:1256:15)
    at InterceptingListener._callNext (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:564:42)
    at InterceptingListener.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:614:8)
    at /user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:1019:24

功能代码:

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

admin.initializeApp();
const settings = { timestampsInSnapshots: true };
admin.firestore().settings(settings);

export const onDocUpdate = functions.firestore
  .document("documents/{documentId}")
  .onUpdate((snapshot, context) => {
    console.log("onDocUpdate called ", context.params.documentId);
    const document = snapshot.after.data();
    console.log("Document: ", document);
    if (document.screw) {
      console.log("Document screw exists. ", document.screw);
      const docRef = admin
        .firestore()
        .collection("screws")
        .doc(document.screw);
      return docRef
        .get()
        .then(doc => {
          if (doc.exists) {
            console.log("Screw for document exists.");
          } else {
            console.error(
              "Screw for document not found! ",
              document.screw
            );
          }
        })
        .catch(error => {
          // Here I get the permission error :(
          console.error(
            "Screw for document doc load error!! ",
            error
          );
        });
    } else {
      console.error("Document is not bound to a screw! ", document.id);
    }
    return null;
  });

package.json

{
  "name": "functions",
  "scripts": {
    "lint": "tslint --project tsconfig.json",
    "build": "tsc",
    "serve": "npm run build && firebase serve --only functions",
    "shell": "npm run build && firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "main": "lib/index.js",
  "dependencies": {
    "@google-cloud/firestore": "^0.16.0",
    "firebase-admin": "^6.0.0",
    "firebase-functions": "^2.0.4",
    "protobufjs": "^6.8.8"
  },
  "devDependencies": {
    "tslint": "~5.8.0",
    "typescript": "~2.8.3"
  },
  "private": true
}

我认为这与管理实例的权限有关,但不知道错误可能是什么,我只是按照docs和youtube上的firebase视频中的步骤进行操作。

我的帐户仍处于免费计划中,并且我在日志中收到一条通知,我应该配置计费帐户,但是如果了解正确的文档,我应该可以访问Google Cloud Platform中的服务,因此读取同一数据库中的其他节点应该没有问题。

我已经在stackoverflow上找到了两个类似的问题,但是没有找到解决方案。也许其他人同时也遇到了这个问题并能够解决?

PERMISSION_DENIED Firestore CloudFunction TypeScriptFirebase error writing to Firestore via a Function: "7 PERMISSION_DENIED: Missing or insufficient permissions"

更新1:的新timestampsInSnapshots设置存在另一个问题。此问题已得到修复,上面的代码已更新。拒绝的主要问题权限仍然存在。

更新2 :关于下面@RonRoyston的回答。这是一个Cloud Function,它使用firebase-admin软件包中的Admin SDK读取节点。因此,它不应受到Firestore安全规则的影响。 @DougStevenson提到的一个链接问题中已经有一个comment。基于Admin SDK documentation,通过调用admin.initializeApp()对其进行初始化就足够了,但是不幸的是,事实并非如此。我没有读过在使用Cloud Functions时在服务帐户或安全规则中需要应用任何特殊IAM设置的地方,因此我没有涉及任何这些设置。

干杯, 拉斯

6 个答案:

答案 0 :(得分:2)

我在使用Cloud Functions时遇到了同样的问题。通过删除/重新部署功能无法解决我的问题。事实证明,在供应我的项目时,没有添加默认服务帐户的IAM角色。我必须在IAM管理面板中为Editor添加一个<project-name>@appspot.gserviceaccount.com角色。

答案 1 :(得分:1)

我终于可以正常工作了。我没有更改任何Firestore安全规则或任何IAM内容。我删除了在us-central1上运行的功能。再次创建了相同的Cloud Function项目,将其复制到我现有的代码中,但是这次我将其部署到europe-west1,并且可以立即使用。

我认为在首次部署到us-central1的过程中,某些事情可能会失败,在那之后,即使我多次删除并重新部署了该函数,我的项目仍会出现错误。不知道到底发生了什么,因为没有显示明显的错误。 Firebase团队的某个知道内部工作流程的人可能会告诉我们是否会发生这种情况,如果是,则如何处理。

目前,上述步骤解决了我的问题。

答案 2 :(得分:0)

我遇到了相同的错误,在任何地方都找不到解决方案,因此,如果可以帮助某人,我将其发布在这里...

我们使用2个Firebase项目(DEV,PROD),并在两个项目上部署相同的功能。当您在:

中指定错误的projectId时,也会出现PERMISSION_DENIED
admin.initializeApp({projectId: 'your_project_id'});

答案 3 :(得分:0)

我有同样的问题。就像nvitius一样,我通过更改权限来解决了。

创建功能时,默认服务帐户似乎为<project-name>@appspot.gserviceaccount.com

您可以通过点击Environment variables, networking, timeouts and more链接进行检查:

To show Service Account

然后您可以验证该帐户或将其更改为“ App Engine默认服务帐户”:

App Engine default service account

此后,我去了IAM验证此服务帐户具有的权限。

但是IAM没有列出/添加此服务帐户。

因此,我将其添加>>添加>>新成员。开始输入内容,然后输入项目ID,然后在下拉菜单中弹出服务帐户。

然后我授予它以下权限:

  • 项目>>编辑器(可能已经有了)
  • 数据存储>>云数据存储所有者
  • 存储>>存储管理员

希望这会有所帮助。

答案 4 :(得分:0)

一个对我有用的解决方案:

  • 我在想要模拟Cloud Function并在Firestore中查看生产结果的Firebase项目之间进行切换(我已经让Cloud Function在项目的Firestore产品中创建数据(例如“ project-dev”)< / li>
  • 即使我正在使用下载的新项目的serviceAccount凭据(“ project-sandbox”),通过云功能在Firestore中通过云功能创建新文档时,权限拒绝错误仍然会发生
let serviceAccount = require('../credentials-sb.json');
admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://<project>-sandbox.firebaseio.com"
});
  • 我注意到我尚未为新项目运行firebase use命令,也未将其添加到.firebaserc中。我正在“使用”一个除凭据文件所需要的项目以外的项目(例如:Firebase CLI设置为使用“ project-dev”,我尚未为新的“ project-project”运行firebase use命令沙箱”)
  • 运行firebase use project-sandbox之后,我运行npm run shell并从模拟器执行了我的功能,一切正常。仿真器在“ project-sandbox”中的工作与在“ project-dev”中的工作一样。

我只能假定这是由于设置了一个project-id环境变量,该变量可以在运行admin.initializeApp()时从环境中检测到,或者可以像这样手动设置(请参见上面@Seb的评论):

let serviceAccount = require('../credentials-sb.json');
admin.initializeApp({
    project-id: '<project>-sandbox'
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://inkling-sandbox.firebaseio.com"
});

我希望这会有所帮助!请告诉我是否可以。

答案 5 :(得分:-1)

我的解决方案是设置serviceAccount,请检查以下代码段:

var admin = require("firebase-admin");

var serviceAccount = require("path/to/serviceAccountKey.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://appycasa-dev-appysphere.firebaseio.com"
});

您可以在以下位置生成serviceAccountKey: Firebase仪表板->项目设置->服务帐户标签

希望有帮助!