【问题标题】:Firestore Security Rules: Allow User To Create Doc Only If New Doc ID is same as User IDFirestore 安全规则:仅当新文档 ID 与用户 ID 相同时才允许用户创建文档
【发布时间】:2019-03-30 07:02:15
【问题描述】:

当用户第一次登录时,我还需要调用一个函数,该函数在我的 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;

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;
}

【问题讨论】:

  • 您找到解决方案了吗?在我的 Firestore 项目中,我一直在苦苦挣扎

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


【解决方案1】:

更新

我最近不得不更新我的规则集,因为 Firestore 规则的工作方式发生了一些变化,并且“getAfter”函数的工作方式也发生了变化。具体来说,我现在可以将 request.resource 用于数据comarisons。无论如何,现在看来我可以用更简单的规则来实现我的目标,所以我想我会更新这个答案并分享。

目标

  • 只有当新文档 ID 与其用户 ID 匹配时,用户才能创建文档。
  • 用户不能将自己声明为“管理员”,如果“管理员”是一个字段,则阻止创建/更新/写入请求(除非他们已经是管理员)
service cloud.firestore {
  match /databases/{database}/documents {
  
    // Allow users to create a document for themselves in the users collection
    match /users/{document=**} {
      allow create: if request.resource.id == request.auth.uid &&
        !("admin" in request.resource.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 - unless they are already an admin
      allow write, update: if request.auth.uid == userId &&
        (
          !("admin" in request.resource.data) ||
          get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true // allow admin to update their own profile
        )

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

旧答案

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

这个新的规则结构完成了以下工作

第一部分,用于创建规则

  • 允许唯一经过身份验证的用户仅在“用户”集合中创建文档 (在用户设置过程中,将自动创建一个文档,其 ID 与其用户 ID 相同)。
  • 不允许创建包含“admin”字段的文档,这表明他们正在尝试获得管理员访问权限。
  • 似乎无法在创建期间验证文档的 id,因此下面有额外的写入/更新规则

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

  • 允许用户仅读取/写入/更新 ID 与其用户 ID 相同的文档(用户尝试创建 ID 与其用户 ID 不同的文档会失败,同时也防止用户创建垃圾邮件通过操纵客户端 JS 请求来处理大量文档。)
  • 不允许用户编写/更新他们的个人资料以包含“管理员”字段

规则

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);
        }
      }
    }

附言 这根本不直观,所以如果有人有更好的解决方法,请发布。另外,我真的希望一旦 firestore 1.0 发布,它会给规则和规则文档带来一些巨大的改进。

【讨论】:

  • 这如何阻止具有 uid abc 的用户创建另一个具有 uid xyz 的用户文档?
  • 正如我上面提到的,在创建时验证文档的 ID 似乎是不可能的,但我可以阻止用户编写或更新文档,除非它是为了他们的 ID - 这已经足够好了.
【解决方案2】:

有点晚了,但我设法调整了您的一个可能的解决方案并使其发挥作用:

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

只需将database 变量替换为(default)。是的,不花哨……

【讨论】:

    【解决方案3】:

    我想出的解决方案。我的测试表明,除了自己的 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();
            }
          }
        }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-22
      • 2022-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-19
      相关资源
      最近更新 更多