Firestore安全规则:仅当新文档ID与用户ID相同时,才允许用户创建文档

时间:2018-10-25 15:33:17

标签: firebase google-cloud-firestore firebase-security-rules

当用户首次登录时,我还需要调用一个函数,该函数在我的firestore用户集合中创建一个文档来存储其个人资料数据。使用Web SDK。

(我以前使用的是带有Firebase函数的新的用户触发事件,但它太慢,无法等待冷函数启动)。

安全规则要求

需要确保用户只能在文档ID与他们的用户ID相同的情况下创建文档(以防止用户创建其他文档)。需要确保此文档尚不存在。

尝试-在模拟器中运行,而不是IRL

这些测试通过模拟器,但不通过IRL。

// Allow users to create a doc if the doc ID == their user id
allow create: if path("/databases/" + database + "/documents/users/" + request.auth.uid) == request.path;

OR

allow create: if /databases/$(database)/documents/users/$(request.auth.uid) == request.resource['__name__']

也尝试过此操作(同样,可以在模拟器中使用,但不能在IRL中使用)

match /users/{userId} {
    // Allow users to read their own profile
    allow create: if request.auth.uid == userId;
}

3 个答案:

答案 0 :(得分:1)

所以我想出了一种解决方法。我还具有一些其他写入/更新条件,这些条件阻止用户更改其权限级别。这是由于某种原因,阻止了任何“创造”的发生。因此,我不得不在创建和写入/更新规则中反映相同的条件。由于某些原因,这是必要的。

此新规则结构可实现以下功能

第一部分,用于创建规则

  • 仅允许经过身份验证的用户创建文档,仅在“用户”集合中(在用户设置过程中,系统会自动使用与用户ID相同的ID创建文档)。
  • 不允许创建包含“ admin”字段的文档,这表明他们试图获取管理员访问权限。
  • 似乎无法在创建过程中验证文档ID,因此下面提供了其他写入/更新规则

第二部分-读取,更新,写入

  • 允许用户仅读取/写入/更新具有与其用户ID相同ID的文档(尝试创建其用户ID以外的ID的文档的用户将失败,也可以防止用户向其发送垃圾邮件客户端JS请求处理大量文档。)
  • 不允许用户编写/更新其个人资料以包括“ admin”字段

规则

service cloud.firestore {

      match /databases/{database}/documents {

        // Allow users to create documents in the user's collection
        match /users/{document=**} {
          allow create: if request.auth.uid != null &&
            !("admin" in getAfter(/databases/$(database)/documents/users/$(request.auth.uid)).data);
        }

        // Allow users to read, write, update documents that have the same ID as their user id
        match /users/{userId} {   
            // Allow users to read their own profile (doc id same as user id)
          allow read: if request.auth.uid == userId;

          // Allow users to write / update their own profile as long as no "admin" field is trying to be added or created
          allow write, update: if request.auth.uid == userId &&
            !("admin" in getAfter(/databases/$(database)/documents/users/$(request.auth.uid)).data);
        }
      }
    }

PS 这一点都不直观,因此,如果有人有更好的解决方法,请发布它。另外,我真的希望firestore 1.0推出后,它将对规则和规则文档带来一些巨大的改进。

答案 1 :(得分:0)

有点晚了,但是我设法调整了一种可能的解决方案并使之生效:

allow create: if path("/databases/(default)/documents/users/" + request.auth.uid) == request.path;

只需将database变量替换为(default)。是的,不要幻想...

答案 2 :(得分:0)

我想出了解决方案。我的测试表明,除了自己的uid之外,无法创建其他用户文档,并且它阻止了普通用户更改任何管理员状态。



    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {

        function isAdmin() {
          return get(/databases/$(database)/documents/users/$(request.auth.uid)).isAdmin == true ||
                 get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true;
        }
        function signedIn(){
            return request.auth.uid != null;
        }

        match /users/{user} {

          // allow updates to own user-doc
          allow read, update, delete: if request.auth.uid == user &&

            // allow updates to own user-doc if "isAdmin" field is the same as before the update (in case user was already admin)
            (request.resource.data.isAdmin == resource.data.isAdmin ||

                // or allow updates if "isAdmin" will be set to false
                request.resource.data.isAdmin == false ||

                // or allow updates if no "isAdmin" field exists after the update
                !("isAdmin" in getAfter(/databases/$(database)/documents/users/$(request.auth.uid)).data)
            );

          // allow creation of user-doc with own uid and no others       
          allow create: if request.auth.uid == user &&

            // if no "isAdmin" field is set
            !("isAdmin" in getAfter(/databases/$(database)/documents/users/$(request.auth.uid)).data);

          // give full access to admins
          allow read, write: if isAdmin();
        }
      }
    }