编写安全规则的条件

本指南以设计安全规则结构指南为基础,介绍如何向 Cloud Firestore 安全规则添加条件。如果您不熟悉 Cloud Firestore 安全规则的基础知识,请参阅入门指南。

Cloud Firestore 安全规则的主要构成元素是条件。条件是一个布尔表达式,用于确定应该允许还是拒绝执行特定操作。使用安全规则可以编写条件来检查用户身份验证情况、验证传入数据,甚至还可访问数据库的其他部分。

身份验证

最常见的安全规则模式之一是基于用户的身份验证状态来控制访问权限。例如,您可能希望应用只允许已登录用户写入数据:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth.uid != null;
    }
  }
}

另一种常见模式是确保用户只能读写自己的数据:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches the 'author_id' field
    // of the document
    match /users/{user} {
      allow read, update, delete: if request.auth.uid == resource.data.author_id;
      allow create: if request.auth.uid != null;
    }
  }
}

如果您的应用使用 Firebase 身份验证,则 request.auth 变量将包含供客户端请求数据的身份验证信息。如需详细了解 request.auth,请参阅参考文档

数据验证

许多应用都将访问权限控制信息以字段形式存储在数据库中的文档内。Cloud Firestore 安全规则可以根据文档数据动态地允许或拒绝访问:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

resource 变量是指所请求的文档,resource.data 是存储在文档中的所有字段和值的映射。如需详细了解 resource 变量,请参阅参考文档

在写入数据时,您可能希望将传入数据与现有数据进行比较。在这种情况下,如果您的规则集允许待执行的写入,则 request.resource 变量将包含相应文档的未来状态。对于仅修改文档的部分字段的 update 操作,request.resource 变量会包含待处理文档在此操作之后的状态。您可以查看 request.resource 中的字段值,以防出现不需要或不一致的数据更新:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

访问其他文档

利用 get()exists() 函数,您的安全规则可以针对数据库中的其他文档评估传入请求。get()exists() 函数都需要指定完整的文档路径。使用变量为 get()exists() 构建路径时,您需要使用 $(variable) 语法对变量进行明确转义。

在以下示例中,database 变量会被 match 语句 match /databases/{database}/documents 捕获,并用于构建路径:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if exists(/databases/$(database)/documents/users/$(request.auth.uid))

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
    }
  }
}

对于写入操作,您可以使用 getAfter() 函数在写入事务或批量写入操作完成后,但在写入事务或批量写入操作提交之前访问文档的状态。和 get() 一样,getAfter() 函数采用完全指定的文档路径。您可以使用 getAfter() 来指定必须作为写入批量操作或写入事务的一部分一起进行的一组写入操作。

自定义函数

随着您的安全规则变得越来越复杂,您可能需要将条件集封装在函数中,以便在规则集中重复使用。安全规则支持自定义函数。自定义函数的语法有点类似于 JavaScript,但安全规则函数是用域特定语言编写的,该语言具有以下一些重要限制:

  • 函数只能包含一个 return 语句,不能包含任何额外的逻辑。例如,它们不能创建中间变量、执行循环或调用外部服务。
  • 函数可以自动访问其定义所属范围内的函数和变量。例如,在 service cloud.firestore 范围内定义的函数可以访问 resource 变量以及 get()exists() 等内置函数。
  • 函数可以调用其他函数,但可能无法递归。调用堆栈总深度不得超过 10。

函数是用 function 关键字定义的,没有参数或具有多个参数。例如,您可能想要将上述示例中使用的两种条件组合成一个函数:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

在安全规则中使用函数可以在规则变得越来越复杂时使其更易于维护。如需详细了解开发者定义的函数,请参阅参考文档

后续步骤

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面