了解“面向 Cloud Storage 的 Firebase 安全规则”语言的核心语法

面向 Cloud Storage 的 Firebase 安全规则允许您控制对 Cloud Storage 存储桶中存储的对象的访问权限。灵活的规则语法让您能够创建规则来控制任何操作,其中包括对 Cloud Storage 存储桶执行的所有写入操作和对特定文件的操作。

本指南介绍了用于创建完整规则集的 Cloud Storage 安全规则的基本语法和结构。

服务和数据库声明

面向 Cloud Storage 的 Firebase 安全规则始终以下列声明开头:

service firebase.storage {
    // ...
}

service firebase.storage 声明将规则限制为在 Cloud Storage 范围内有效,以防止 Cloud Storage 安全规则与其他产品(例如 Cloud Firestore)的规则发生冲突。

基本的读取/写入规则

基本规则包括:一个用于标识 Cloud Storage 存储桶的 match 语句、一个用于指定文件名的 match 语句,以及一个用于详细说明何时允许读取指定数据的 allow 表达式。allow 表达式指定涉及的“访问方式”(例如,读取、写入)以及允许或拒绝访问的“条件”

在默认规则集中,第一个 match 语句使用 {bucket} 通配符表达式来指明规则适用于项目中的所有存储桶。在下一部分中,我们将讨论通配符匹配的概念。

service firebase.storage {
  // The {bucket} wildcard indicates we match files in all Cloud Storage buckets
  match /b/{bucket}/o {
    // Match filename
    match /filename {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

所有 match 语句均指向文件。Match 语句可以指向特定文件,如 match /images/profilePhoto.png 中所示。

匹配通配符

除了指向单个文件之外,规则可以使用通配符指向名称中包含给定字符串前缀(包括斜杠)的任何文件,如 match /images/{imageId} 中所示。

在上面的示例中,match 语句使用了 {imageId} 通配符语法。这意味着,该规则适用于名称以 /images/ 开头的任何文件,例如 /images/profilePhoto.png/images/croppedProfilePhoto.png。在对 match 语句中的 allow 表达式求值时,imageId 变量将解析为图片文件名,例如 profilePhoto.pngcroppedProfilePhoto.png

可以从 match 中引用通配符变量来提供文件名或路径授权:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

分层数据

前面提到过,Cloud Storage 存储桶中没有层次结构。但是,通过使用文件命名惯例(通常在文件名中包含斜杠),我们可以模仿看起来像一系列嵌套目录和子目录的结构。了解 Firebase 安全规则如何与这些文件名进行交互是非常重要的。

假设有一组名称都以 /images/ 主干开头的文件。Firebase 安全规则仅适用于匹配的文件名,因此针对 /images/ 主干定义的访问权限控制措施不适用于 /mp3s/ 主干。不过,您可以编写明确的规则来与不同的文件名模式匹配:

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      allow read, write: if <condition>;
    }

    // Explicitly define rules for the 'mp3s' pattern
    match /mp3s/{mp3Id} {
      allow read, write: if <condition>;
    }
  }
}

嵌套 match 语句时,内层 match 语句的路径始终附加到外层 match 语句的路径中。因此,以下两个规则集是等效的:

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      // Exact match for "images/profilePhoto.png"
      match /profilePhoto.png {
        allow write: if <condition>;
      }
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Exact match for "images/profilePhoto.png"
    match /images/profilePhoto.png {
      allow write: if <condition>;
      }
  }
}

递归匹配通配符

除了匹配并返回文件名末尾字符串的通配符之外,还可以通过在通配符名称中添加 =**(例如 {path=**})来声明多段通配符以进行更复杂的匹配:

// Partial match for files that start with "images"
match /images {

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

如果有多个规则与一个文件相匹配,所有规则求得的值之间为 OR 关系。也就是说,如果任何一个与该文件匹配的规则求得的值为 true,结果就为 true

在上述规则中,只要 conditionother_condition 中任何一个求得的值为 true,就可以读取文件“images/profilePhoto.png”;而只有当 other_condition 求得的值为 true 时,才能读取文件“images/users/user:12345/profilePhoto.png”。

Cloud Storage 安全规则不采用级联形式,只有当请求的路径与指定了规则的路径匹配时才会对规则求值。

版本 1

Firebase 安全规则默认使用版本 1。在版本 1 中,递归通配符与一个或多个文件名元素(而不是零个或零个以上元素)匹配。因此,match /images/{filenamePrefixWildcard}/{imageFilename=**} 会与 /images/profilePics/profile.png 这样的文件名匹配,而不会与 /images/badge.png 匹配。请改用 /images/{imagePrefixorFilename=**}

递归通配符必须位于匹配语句的末尾。

我们建议您使用版本 2 以获得更强大的功能。

版本 2

在 Firebase 安全规则的版本 2 中,递归通配符与零个或更多路径项匹配。因此,/images/{filenamePrefixWildcard}/{imageFilename=**} 会与文件名 /images/profilePics/profile.png 和 /images/badge.png 匹配。

您必须在安全规则的第一行添加 rules_version = '2'; 来选择启用版本 2:

rules_version = '2';
service cloud.storage {
  match /b/{bucket}/o {
   ...
 }
}

每个匹配语句中最多只能使用一个递归通配符,但在版本 2 中,可以将此通配符放在匹配语句的任何位置。例如:

rules_version = '2';
service firebase.storage {
 match /b/{bucket}/o {
   // Matches any file in a songs "subdirectory" under the
   // top level of your Cloud Storage bucket.
   match /{prefixSegment=**}/songs/{mp3filenames} {
     allow read, write: if <condition>;
   }
  }
}

细化的操作

在某些情况下,将 readwrite 细分为更细化的操作很有用。例如,您的应用可能希望针对创建文件操作和删除文件操作分别强制使用不同的条件。

read 操作可细分为 getlist

write 规则可细分为 createupdatedelete

service firebase.storage {
  match /b/{bucket}/o {
    // A read rule can be divided into read and list rules
    match /images/{imageId} {
      // Applies to single file read requests
      allow get: if <condition>;
      // Applies to list and listAll requests (Rules Version 2)
      allow list: if <condition>;

    // A write rule can be divided into create, update, and delete rules
    match /images/{imageId} {
      // Applies to writes to file contents
      allow create: if <condition>;

      // Applies to updates to (pre-existing) file metadata
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
 }
}

重叠的匹配语句

一个文件名有可能会与多个 match 语句匹配。如果有多个 allow 表达式与某个请求匹配,则只要任何一个条件为 true,就允许访问文件:

service firebase.storage {
  match b/{bucket}/o {
    // Matches file names directly inside of '/images/'.
    match /images/{imageId} {
      allow read, write: if false;
    }

    // Matches file names anywhere under `/images/`
    match /images/{imageId=**} {
      allow read, write: if true;
    }
  }
}

在上面的示例中,因为第二条规则始终为 true,所以允许对名称以 /images/ 开头的文件执行所有读写操作,即使第一条规则为 false 也是如此。

规则并非过滤条件

当您确保数据安全无虞并开始执行文件操作后,请谨记,安全规则不是过滤条件。既希望对一组与某个文件名模式匹配的文件执行操作,又希望 Cloud Storage 仅访问当前客户端有权访问的文件,这是无法实现的。

以下面的安全规则为例:

service firebase.storage {
  match /b/{bucket}/o {
    // Allow the client to read files with contentType 'image/png'
    match /aFileNamePrefix/{aFileName} {
      allow read: if resource.contentType == 'image/png';
    }
  }
}

拒绝:此规则拒绝以下请求,因为结果集可能包含 contentType 不为 image/png 的文件:

Web
filesRef = storage.ref().child("aFilenamePrefix");

filesRef.listAll()
    .then(function(result) {
      console.log("Success: ", result.items);
    })
});

Cloud Storage 安全规则中的规则会根据每个查询的潜在结果对其进行评估,如果返回的可能是客户端无权读取的文件,那么该请求会失败。访问请求必须遵循您的规则所设置的限制条件。

后续步骤

您可以深入了解面向 Cloud Storage 的 Firebase 安全规则:

您可以浏览特定于 Cloud Storage 的 Firebase 安全规则使用场景: