首页 > 解决方案 > 如何授予基于其他集合的用户的集合访问权限?

问题描述

假设有 3 个集合并且它们处于相同的层次结构级别:

  1. 用户
  2. UserAndOtherCollectionRelationship
  3. 其他收藏

我希望向拥有该记录或与之相关的用户授予对“OtherCollection”记录的访问权限(仅读取访问权限)。

将“UserAndOtherCollectionRelationship”理解为

UserAndOtherCollectionRelationship: {
    'userId': uid, //user id provided by Firebase Auth Service
    'otherCollectionId': 000,
    'roles': ['owner', 'reader', ...]
}

这就是我所拥有的:

match /databases/{database}/documents {

  match /otherCollection/{otherCollectionId} {
    allow read, update, delete: if(isOtherCollectionOwner());
    allow create: if(isSignedIn());
  }

  match /user/{userId} {
    allow read, write: if(isSignedIn() && isUserOwner(userId));
  }

  match /userAndOtherCollectionRelationship/{userAndOtherCollectionRelationshipId} {
    allow read: if(resource.data.userId == request.auth.uid && isSignedIn());
    allow create: if(isSignedIn());
    allow update, delete: if(resource.data.userId == request.auth.uid);
  }

  // Functions
  function isSignedIn() {
    return request.auth != null;
  }

  function isUserOwner(userId) {
    return request.auth.uid == userId;
  }

  function isOtherCollectionOwner() {
    return isUserOwner(getUserAndOtherCollectionRelationshipData().userId) && getOtherCollectionData().roles.hasAll(['owner']);
  }

  //This is the function that I believe that it's not working propertly
  function getuserAndOtherCollectionRelationshipData() {
    return get(/databases/$(database)/documents/userAndOtherCollectionRelationship/{document=**}).data; 
  }
}

考虑到客户端(应用程序)必须创建一个过滤器(where 子句)来仅获取所需的记录,我也找不到使用此模式的方法。

所以我把用户角色作为一个字段放在“otherCollection”记录上:

otherCollection: {
    ...,
    'userAndRoles': {
        'replaceByUID': ['owner', ...]
    },
}

将安全规则功能更新为:

function isOtherCollectionOwner() {
    return get(/databases/$(database)/documents/OtherCollection/$(otherCollectionId)).data.roles[request.auth.uid].hasAll(['owner']);
}

这是客户电话:

final querySnapshot = await firestore.collection('otherCollection')
    .where('user.$userId', arrayContains: 'owner')
    .where('otherCollectionId', whereIn: otherCollectionIdList)
    .get();

什么是最好的解决方案?将数据模型更改为... 将不同的安全规则设置为...

标签: firebasefluttergoogle-cloud-firestorefirebase-security

解决方案


为了解决这个问题,我更新了数据模型,删除了 userAndOtherCollectionRelationship 集合,并将 owner 属性添加到 otherCollection。

任何其他关系都将作为属性添加到 otherCollection。

所以 otherCollection 现在看起来像这样:

otherCollection: {
    owner: ["user_uid", "other_user_id"],
    ..., //other atributes
}

安全规则更新为:

match /otherCollection/{otherCollectionId} {
    allow read, update, delete: if(isOtherCollectionOwner());
    allow create: if(isSignedIn());
}
function isOtherCollectionOwner() {
  return ([request.auth.uid] in (resource.data.owner));
}

安全规则测试已更新为:

const myAuth = {uid: 'my_user_uid', email: 'my@mail.com'};
const MY_PROJECT_ID = "my_project_id";

function getAdminFirestore() {
    return firebase.initializeAdminApp({projectId: MY_PROJECT_ID, auth: myAuth}).firestore();
}

function getFirestore(auth) {
    return firebase.initializeTestApp({projectId: MY_PROJECT_ID, auth: auth}).firestore();
}

describe("MyApp", () => {
    it("Can list if is owner", async () => {
        const admin = getAdminFirestore();
        const setupOtherCollection = admin.collection('otherCollection').doc('otherCollectionId');
        await setupOtherCollection.set({'name': 'myOtherCollection', 'owner': [myAuth.uid]});
    
        const db = getFirestore(myAuth);
        const otherCollectionCollection = db.collection("otherCollection").where("owner", "array-contains", [myAuth.uid]);
        await firebase.assertSucceeds(otherCollectionCollection.get());
    });
});

推荐阅读