面向 Cloud Storage 的 Firebase Security Rules 与 Firebase 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; }
群组私有
另一个同样常见的使用场景是为群组提供对象权限,例如允许多名团队成员协同撰写或修改某个共享的文档。下列几种方法可以实现这个目的:
将这些数据存储在令牌或文件元数据中后,就可以在规则中引用这些数据:
// 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; } } } }