Firebase Realtime Database 安全规则确定哪些用户有权读取和写入您的数据库、数据结构如何,以及存在哪些索引。这些规则存在于 Firebase 服务器上,并且始终自动执行。每一个读取和写入请求只有在您的规则允许时才能完成。默认情况下,您的规则不允许任何人访问您的数据库。这是为了在您有时间自定义规则或设置身份验证之前,防止数据库被滥用。
Realtime Database 安全规则使用类似于 JavaScript 的语法,包括四种类型。
规则类型 | |
---|---|
.read | 描述是否以及何时允许用户读取数据。 |
.write | 描述是否以及何时允许写入数据。 |
.validate | 定义值的正确格式、值是否包含子属性以及值的数据类型。 |
.indexOn | 指定用于编制索引的子属性,以支持排序和查询。 |
Realtime Database 安全概览
Firebase Realtime Database 提供用于管理应用安全性的一整套工具。借助这些工具,可以轻松验证用户身份、实施用户权限和验证输入。
与许多其它可选择的技术相比,基于 Firebase 的应用更多地运行客户端代码。因此,我们实现安全性的方法可能与您以往使用的方法略有不同。
身份验证
确保应用安全的第一步常常是识别用户。此过程称为“身份验证”。您可以使用 Firebase Authentication 功能让用户登录到您的应用。Firebase Authentication 支持为各种常见的身份验证方法(如 Google 和 Facebook、电子邮件地址和密码登录、匿名登录等等)使用访客身份验证。
用户身份是一个重要的安全概念。不同的用户拥有不同的数据,有时他们还拥有不同的权限。例如,在聊天应用中,每条消息均与创建该消息的用户关联。用户也可以删除自己的消息,但不能删除其他用户发布的消息。
授权
识别用户只是保证安全的一部分。在知道用户是谁后,您需要一种方式控制用户对数据库中数据的访问。Realtime Database 安全规则允许您控制每个用户的访问权限。例如,下面是一组安全规则,允许任何人读取路径 /foo/
,但不允许任何人对其进行写入:
{ "rules": { "foo": { ".read": true, ".write": false } } }
.read
和 .write
规则级联,因此该规则集授予对路径 /foo/
以及任何更深路径(如 /foo/bar/baz
)中任何数据的读取权限。请注意,位于数据库中浅层的 .read
和 .write
规则将会覆盖深层规则,因此在此例中仍将授予对 /foo/bar/baz
的读取权限,尽管 /foo/bar/baz
路径下的规则求得的值为 False。
Realtime Database 安全规则包含内置变量和函数,您可以利用它们引用其他路径、服务器端时间戳、身份验证信息等等。以下是一个规则的示例,该规则向已通过身份验证的用户授予对 /users/<uid>/
的写入权限,其中 <uid> 是通过 Firebase Authentication 获取的用户 ID。
{ "rules": { "users": { "$uid": { ".write": "$uid === auth.uid" } } } }
数据验证
Firebase Realtime Database 属于无架构数据库。这样可以在开发过程中轻松修改数据,但一旦准备发行应用,就需要保持数据的一致性,这一点非常重要。规则语言包括一个 .validate
规则,允许您使用与 .read
和 .write
规则所用表达式相同的表达式来应用验证逻辑。唯一的不同之处在于验证规则不级联,因此所有相关的验证规则求得的值必须为 true,才允许写入。
这些规则强制规定,写入 /foo/
的数据必须为少于 100 个字符的字符串:
{ "rules": { "foo": { ".validate": "newData.isString() && newData.val().length < 100" } } }
验证规则可以访问所有与 .read
和 .write
规则相同的内置函数和变量。您可以使用这些函数和变量来创建能够识别数据库中其他位置的数据、用户身份、服务器时间等信息的验证规则。
定义数据库索引
Firebase Realtime Database 允许排序和查询数据。对于少量数据,数据库支持临时查询,因此在开发过程中一般不需要索引。但是在发布您的应用之前,对于需要在应用不断成长的过程中确保始终高效运行的任何查询,为其指定索引非常重要。
索引通过 .indexOn
规则指定。以下是索引声明的示例,将为恐龙列表的高度和长度字段编制索引:
{ "rules": { "dinosaurs": { ".indexOn": ["height", "length"] } } }