TLDR: 这是一个关于从
task.snapshot.ref.getDownloadURL()
返回的 URL 及其各自的 downloadToken
的问题。它询问 token
的主要作用和功能是什么,以及根据安全规则公开的文件是否有必要。
我刚刚完成了有关将文件上传和下载到 Firebase Storage 的教程指南,可在 https://firebase.google.com/docs/storage/web/upload-files 以及此 Youtube 教程中找到来自 Firebase 官方渠道。
我正在为我的一个 Firebase Web 应用程序(React + Firebase)中的博客部分构建内容管理系统。
我有一个组件,允许管理员选择图像并将其上传到 Firebase 存储桶以显示在特定的博客文章中。特定
blogPost
的所有图像都应位于特定 blog-post-slug
的文件夹内。
示例:
//bucket/some-blog-post-slug/image1.jpg
每当管理员在
<input type='file'/>
上选择新文件时运行的代码:
function onFileSelect(e) {
const file = e.target.files[0];
const storageRef = firebase.storage().ref('some-slug/' + file.name);
const task = storageRef.put(file);
task.on('state_changed',
function progress(snapshot) {
setPercent((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
},
function error(err) {
console.log(err);
},
function complete() {
console.log('Upload complete!');
task.snapshot.ref.getDownloadURL().then(function(downloadURL) {
console.log('File available at', downloadURL);
props.changeImageSrc(downloadURL);
});
}
);
}
上面的代码返回将保存到
downloadURL
文档内的 Firestore 的 blogPost
。
downloadURL
具有以下格式:
https://firebasestorage.googleapis.com/v0/b/MYFIREBASEAPP.appspot.com/o/some-slug%2FILE_NAME.jpg?alt=media&token=TOKEN_VALUE
你可以看到它带有一个“基本URL”:
https://firebasestorage.googleapis.com/v0/b/MYFIREBASEAPP.appspot.com/o/some-slug%2FILE_NAME.jpg
并且 basicURL 附加有以下 GET 参数:
alt=media
和 token=TOKEN_VALUE
我不知道我会获得令牌,所以我现在正在测试它的行为以了解更多信息。
允许存储读取的行为:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}}}
{
"name": "some-slug/FILE_NAME.jpg",
"bucket": "MYBUCKET",
"generation": "GENERATION_NUMBER",
"metageneration": "1",
"contentType": "image/jpeg",
"timeCreated": "2019-06-05T13:53:57.070Z",
"updated": "2019-06-05T13:53:57.070Z",
"storageClass": "STANDARD",
"size": "815155",
"md5Hash": "Mj4aCPs21NUNxXpKg1bHirFIO0A==",
"contentEncoding": "identity",
"contentDisposition": "inline; filename*=utf-8''FILE_NAME.jpg",
"crc32c": "zhkQMQ==",
"etag": "CKu4a1+u2+0ucI412CEAE=",
"downloadTokens": "TOKEN_VALUE"
}
图像已显示。
当我访问basicURL时?alt=media&token=TOKEN_VALUE
存储读取受限的行为:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}}}
{
"error": {
"code": 403,
"message": "Permission denied. Could not perform this operation"
}
}
{
"error": {
"code": 403,
"message": "Permission denied. Could not perform this operation"
}
}
结论和问题
在我看来,安全规则
allow read: if request.auth != null;
应该阻止未经授权的用户的任何读取,但是使用TOKEN
参数,即使对于没有auth
对象的请求也可以访问该文件(注意:我没有记录当我运行上面的测试时)。
我知道提出超过 1 个问题并不是最佳做法,但在这种情况下我认为有必要:
问题1:
这个TOKEN主要用于什么以及为什么它会推翻
auth
规则?
问题2:
我希望这些图片能够公开,因为博客部分将面向所有用户。我应该将什么 URL 保存到 Firestore?
选项1:允许所有人读取并仅保存基本URL。
选项 2: 保持读取限制并保存 basicURL + 令牌。
问题3:
要在
<image src="imgSrc">
标签中显示图像,我是否需要 alt=media
参数?或者以 FILE_NAME 结尾的 basicURL 就足够了?
编辑:问题 3 答案:刚刚测试了一下,发现需要
alt=media
GET 参数才能在 <img>
标签内显示图像。
注意:如果您上传相同的文件并替换旧的文件,您每次都会得到不同的
token
,并且旧的token
将失效。
不幸的是,https://firebase.google.com/docs/storage/web/create-reference中描述的方法没有将授权数据添加到请求和存储规则中
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
返回
permission denied
,
使用 AngularFireStorage 模块解决了这个问题。
import { AngularFireStorage } from '@angular/fire/storage';
constructor(
private storage: AngularFireStorage
) {
}
getFileUrl(path: string): Observable<string> {
const storageRef = this.storage.ref(path);
return from(storageRef.getDownloadURL());
}
问题1:
令牌不会覆盖安全规则,而是用于身份验证(类似于存储管理的密码)。
问题2: 您可以编辑规则,以便每个人都可以(全局)访问。
或者通过公开文件来单独决定每个文件,而不是编辑 firestore 规则(据我所知)。
了解更多:https://www.sentinelstand.com/article/guide-to-firebase-storage-download-urls-tokens
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
这是 Firebase 存储的安全权限。所有类型的数据(图像、视频等)