保障用户数据安全

面向 Cloud StorageFirebase Security RulesFirebase Authentication 集成,可为 Cloud Storage 提供基于用户的强大身份验证功能。这样就可以根据 Firebase Authentication 令牌的声明进行精确的访问权限控制。

用户身份验证

当经过身份验证的用户对 Cloud Storage 发出请求时,系统将使用该用户的 uid (request.auth.uid) 以及 Firebase Authentication JWT (request.auth.token) 的声明来填充 request.auth 变量。

另外,当使用自定义身份验证时,request.auth.token 字段中会显示其他声明。

当未经身份验证的用户发出请求时,request.auth 变量为 null

使用这些数据时,可以通过几种常用方法来利用身份验证保护文件:

  • 公开:忽略 request.auth
  • 仅对经过身份验证的用户公开:确定 request.auth 不为 null
  • 用户私有:检查 request.auth.uid 是否等于路径 uid
  • 群组私有:检查自定义令牌的声明是否与所选的声明相匹配,或读取文件元数据以确定某个元数据字段是否存在

公开

任何不考虑 request.auth 上下文的规则均可被视为 public 规则,因为它不考虑用户的身份验证上下文。这些规则适合用于呈现公开数据(如游戏资源、声音文件或其他静态内容)的场景。

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

仅对经过身份验证的用户公开

在某些情况下,您可能希望允许所有经过身份验证的应用用户查看数据,但不允许未经身份验证的用户查看。由于所有未经身份验证的用户的 request.auth 变量均为 null,因此如果要求必须通过身份验证,您只需检查 request.auth 变量是否存在即可:

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

用户私有

到目前为止,request.auth 最常见的使用场景是为个人用户提供对其文件的精细权限,例如上传个人资料照片和读取私人文件等。

因为 Cloud Storage 中的文件具有完整的文件路径,所以若要让用户拥有某个文件的控制权限,只需要在文件路径中包含一个唯一的用户识别信息(例如用户的 uid),在对规则求值时可以检查此信息:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth != null && request.auth.uid == userId;
}

群组私有

另一个同样常见的使用场景是为群组提供对象权限,例如允许多名团队成员协同撰写或修改某个共享的文档。下列几种方法可以实现这个目的:

  • 创建一个 Firebase Authentication 自定义令牌,其中包含有关群组成员的附加信息(例如群组 ID)
  • 文件元数据中包含群组信息(例如群组 ID 或经过授权的 uid 的列表)

将这些数据存储在令牌或文件元数据中后,就可以在规则中引用这些数据:

// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}

完整示例

以下示例中显示了四种常见类型的身份验证限制的简单用例:

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      // Anyone can view any image (no auth, publicly readable)
      match /{allImages=**} {
        allow read;
      }

      // Only authenticated users can write to "public" images
      match /public/{imageId} {
        allow write: if request.auth != null;
      }

      // Only an individual user can write to "their" images
      match /{userId}/{imageId} {
        allow write: if request.auth.uid == userId;
      }

      // Allow a "group" of users to read/write to shared images
      // An owner metadata property on the object contains the groupId for reads
      // A custom token has been minted with a groupId property for writes
      match /{groupId}/{imageId} {
        allow read: if resource.metadata.owner == request.auth.token.groupId;
        allow write: if request.auth.token.groupId == groupId;
      }
    }
  }
}