Javascript Firebase emulator上的Firebase权限被拒绝错误

Javascript Firebase emulator上的Firebase权限被拒绝错误,javascript,firebase,google-cloud-firestore,jestjs,firebase-security,Javascript,Firebase,Google Cloud Firestore,Jestjs,Firebase Security,我在引用Firestore安全规则。我已经从存储库中提取了代码,它与视频匹配。 我更改了设置代码以运行firestore.rules而不是firestore测试。rules,并尝试运行firebase模拟器:start和jest./spec按照相同的目录结构,我未通过测试“当用户是管理员时应允许删除”和“不允许普通用户删除”,失败的原因是由于通配符中的写入规则。有人知道是什么问题吗 collections.spec.js const { setup, teardown } = require("

我在引用Firestore安全规则。我已经从存储库中提取了代码,它与视频匹配。 我更改了
设置
代码以运行
firestore.rules
而不是
firestore测试。rules
,并尝试运行
firebase模拟器:start
jest./spec
按照相同的目录结构,我未通过
测试“当用户是管理员时应允许删除”
“不允许普通用户删除”
,失败的原因是由于通配符中的写入规则。有人知道是什么问题吗

collections.spec.js

const { setup, teardown } = require("./helpers");


describe("General Safety Rules", () => {
  afterEach(async () => {
    await teardown();
  });

  test("should deny a read to the posts collection", async () => {
    const db = await setup();
    const postsRef = db.collection("posts");
    await expect(postsRef.get()).toDeny();
  });

  test("should deny a write to users even when logged in", async () => {
    const db = await setup({
      uid: "danefilled"
    });

    const usersRef = db.collection("users");
    await expect(usersRef.add({ data: "something" })).toDeny();
  });
});

describe("Posts Rules", () => {
  afterEach(async () => {
    await teardown();
  });

  test("should allow update when user owns post", async () => {
    const mockData = {
      "posts/id1": {
        userId: "danefilled"
      },
      "posts/id2": {
        userId: "not_filledstacks"
      }
    };

    const mockUser = {
      uid: "danefilled"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(
      postsRef.doc("id1").update({ updated: "new_value" })
    ).toAllow();

    await expect(postsRef.doc("id2").update({ updated: "new_value" })).toDeny();
  });

  test("should allow delete when user owns post", async () => {
    const mockData = {
      "posts/id1": {
        userId: "danefilled"
      },
      "posts/id2": {
        userId: "not_filledstacks"
      }
    };

    const mockUser = {
      uid: "danefilled"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(postsRef.doc("id1").delete()).toAllow();

    await expect(postsRef.doc("id2").delete()).toDeny();
  });

  test("should allow delete when user is admin", async () => {
    const mockData = {
      "users/filledstacks": {
        userRole: "Admin"
      },
      "posts/id1": {
        userId: "not_matching1"
      },
      "posts/id2": {
        userId: "not_matching2"
      }
    };

    const mockUser = {
      uid: "filledstacks"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(postsRef.doc("id1").delete()).toAllow();
  });

  test("should not allow delete for normal user", async () => {
    const mockData = {
      "users/filledstacks": {
        userRole: "User"
      },
      "posts/id1": {
        userId: "not_matching1"
      },
      "posts/id2": {
        userId: "not_matching2"
      }
    };

    const mockUser = {
      uid: "filledstacks"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(postsRef.doc("id1").delete()).toDeny();
  });

  test("should allow adding a post when logged in", async () => {
    const db = await setup({
      uid: "userId"
    });

    const postsRef = db.collection("posts");
    await expect(postsRef.add({ title: "new_post" })).toAllow();
  });

  test("should deny adding a post when not logged in", async () => {
    const db = await setup();
    const postsRef = db.collection("posts");
    await expect(postsRef.add({ title: "new post" })).toDeny();
  });
});
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {



    // lock down the db
    match /{document=**} {
      allow read: if false;
      allow write: if false;
    }

    match /posts/{postId} {
      allow update: if userOwnsPost();
      allow delete: if userOwnsPost() || userIsAdmin();
      allow create: if loggedIn();
    }

    function loggedIn() {
      return request.auth.uid != null;
    }

    function userIsAdmin() {
      return getUserData().userRole == 'Admin';
    }

    function getUserData() {
      return get(/databases/$(database)/documents/users/$(request.auth.uid)).data
    }

    function userOwnsPost() {
      return resource.data.userId == request.auth.uid;
    }
  }
}
firestore.rules

const { setup, teardown } = require("./helpers");


describe("General Safety Rules", () => {
  afterEach(async () => {
    await teardown();
  });

  test("should deny a read to the posts collection", async () => {
    const db = await setup();
    const postsRef = db.collection("posts");
    await expect(postsRef.get()).toDeny();
  });

  test("should deny a write to users even when logged in", async () => {
    const db = await setup({
      uid: "danefilled"
    });

    const usersRef = db.collection("users");
    await expect(usersRef.add({ data: "something" })).toDeny();
  });
});

describe("Posts Rules", () => {
  afterEach(async () => {
    await teardown();
  });

  test("should allow update when user owns post", async () => {
    const mockData = {
      "posts/id1": {
        userId: "danefilled"
      },
      "posts/id2": {
        userId: "not_filledstacks"
      }
    };

    const mockUser = {
      uid: "danefilled"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(
      postsRef.doc("id1").update({ updated: "new_value" })
    ).toAllow();

    await expect(postsRef.doc("id2").update({ updated: "new_value" })).toDeny();
  });

  test("should allow delete when user owns post", async () => {
    const mockData = {
      "posts/id1": {
        userId: "danefilled"
      },
      "posts/id2": {
        userId: "not_filledstacks"
      }
    };

    const mockUser = {
      uid: "danefilled"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(postsRef.doc("id1").delete()).toAllow();

    await expect(postsRef.doc("id2").delete()).toDeny();
  });

  test("should allow delete when user is admin", async () => {
    const mockData = {
      "users/filledstacks": {
        userRole: "Admin"
      },
      "posts/id1": {
        userId: "not_matching1"
      },
      "posts/id2": {
        userId: "not_matching2"
      }
    };

    const mockUser = {
      uid: "filledstacks"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(postsRef.doc("id1").delete()).toAllow();
  });

  test("should not allow delete for normal user", async () => {
    const mockData = {
      "users/filledstacks": {
        userRole: "User"
      },
      "posts/id1": {
        userId: "not_matching1"
      },
      "posts/id2": {
        userId: "not_matching2"
      }
    };

    const mockUser = {
      uid: "filledstacks"
    };

    const db = await setup(mockUser, mockData);

    const postsRef = db.collection("posts");

    await expect(postsRef.doc("id1").delete()).toDeny();
  });

  test("should allow adding a post when logged in", async () => {
    const db = await setup({
      uid: "userId"
    });

    const postsRef = db.collection("posts");
    await expect(postsRef.add({ title: "new_post" })).toAllow();
  });

  test("should deny adding a post when not logged in", async () => {
    const db = await setup();
    const postsRef = db.collection("posts");
    await expect(postsRef.add({ title: "new post" })).toDeny();
  });
});
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {



    // lock down the db
    match /{document=**} {
      allow read: if false;
      allow write: if false;
    }

    match /posts/{postId} {
      allow update: if userOwnsPost();
      allow delete: if userOwnsPost() || userIsAdmin();
      allow create: if loggedIn();
    }

    function loggedIn() {
      return request.auth.uid != null;
    }

    function userIsAdmin() {
      return getUserData().userRole == 'Admin';
    }

    function getUserData() {
      return get(/databases/$(database)/documents/users/$(request.auth.uid)).data
    }

    function userOwnsPost() {
      return resource.data.userId == request.auth.uid;
    }
  }
}
来自终端的错误跟踪

FirebaseError: 7 PERMISSION_DENIED: 
false for 'create' @ L10


  ● Posts Rules › should not allow delete for normal user

FirebaseError: 7 PERMISSION_DENIED: 
false for 'create' @ L10

  at new FirestoreError (/Users/../../../../../../../../../Resources/rules/node_modules/@firebase/firestore/src/util/error.ts:166:5)
  at ClientDuplexStream.<anonymous> (/Users/../../../../../../../../../Resources/rules/node_modules/@firebase/firestore/src/platform_node/grpc_connection.ts:240:13)
  at ClientDuplexStream._emitStatusIfDone (/Users/../../../../../../../../../Resources/rules/node_modules/grpc/src/client.js:234:12)
  at ClientDuplexStream._receiveStatus (/Users/../../../../../../../../../Resources/rules/node_modules/grpc/src/client.js:211:8)
  at Object.onReceiveStatus (/Users/../../../../../../../../../Resources/rules/node_modules/grpc/src/client_interceptors.js:1311:15)
  at InterceptingListener._callNext (/Users/../../../../../../../../../Resources/rules/node_modules/grpc/src/client_interceptors.js:568:42)
  at InterceptingListener.onReceiveStatus (/Users/../../../../../../../../../Resources/rules/node_modules/grpc/src/client_interceptors.js:618:8)
  at /Users/../../../../../../../../../Resources/rules/node_modules/grpc/src/client_interceptors.js:1127:18
FirebaseError:7权限被拒绝:
对于'create'@L10,为false
● 帖子规则›不允许普通用户删除
FirebaseError:7权限\u被拒绝:
对于'create'@L10,为false
在新FirestoreError(/Users/../../../../../../../../../../../../Resources/rules/node_modules/@firebase/firestore/src/util/error.ts:166:5)
在ClientDuplexStream上。(/Users/../../../../../../../../../../../../../Resources/rules/node\u modules/@firebase/firestore/src/platform\u node/grpc\u connection.ts:240:13)
在ClientDuplexStream上。_emitStatusIfDone(/Users/../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../Resources/rules/node_module
在ClientDuplexStream.\u receiveStatus(/Users/../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../reso
在Object.onReceiveStatus(/Users/../../../../../../../../../../../../../../../Resources/rules/node\u modules/grpc/src/client\u interceptors.js:1311:15)
在拦截侦听器处。_callNext(/Users/./../../../../../../../../../../../../../../../../../../../../../../../../../../../Resources/rules/node_modules/grpc/src/client_interceptors.js
在InterceptingListener.onReceiveStatus(/Users/../../../../../../../../../../../../../../../../../../../../../../Resources/rules/node\u modules/grpc/src/client\u interceptors.js:618:8)
在/Users/../../../../../../../../../../../../../../Resources/rules/node_modules/grpc/src/client_interceptors.js:1127:18

实际上,我遵循相同的教程开始使用firebase emulator,并收到了相同的错误消息。我的问题是,当启动模拟器时,它会自动查找
firestore.rules
文件并加载规则。因此,当您添加
mockData
时,规则已经适用

为了使测试代码正常工作,请将
firebase.json
中firestore规则文件的设置更改为不存在的文件(或允许所有读/写的规则文件),或将
mockData
作为管理员添加到
设置
功能中,例如:

module.exports.setup = async (auth, data) => {
  const projectId = `rules-spec-${Date.now()}`;
  const app = firebase.initializeTestApp({
    projectId,
    auth
  });

  const db = app.firestore();

  // Initialize admin app
  const adminApp = firebase.initializeAdminApp({
    projectId
  });

  const adminDB = adminApp.firestore();

  // Write mock documents before rules using adminApp
  if (data) {
    for (const key in data) {
      const ref = adminDB.doc(key);
      await ref.set(data[key]);
    }
  }

  // Apply rules
  await firebase.loadFirestoreRules({
    projectId,
    rules: fs.readFileSync('firestore.rules', 'utf8')
  });

  return db;
};
希望这有帮助


另请参见

对于目前存在此问题的firestore 8.6.1(或同等版本),这里讨论了一个错误:

修复方法是降级到firestore 8.3.1,或者如果您将来正在阅读此版本,并且firestore>=9.9.0已经发布,请升级到该版本