在 flutter 中,将文件上传到 firebase 存储后,如何获取 public URL?
In flutter, after uploading a file to firebase storage, how do I get the public URL?
我有这些要求:
- 我想上传文件到 firebase 存储。
- 我想存储这些文件的 URL 列表(在 firebase firestore 数据库中)。
- 我想使用存储规则限制查看这些文件。
将文件上传到 firebase 存储非常简单。
var uploadTask = await firebase_storage.FirebaseStorage.instance
.ref(ref)
.putFile(
file,
firebase_storage.SettableMetadata(
customMetadata: _customMetaData(ownerId, readAccess)));
var url = await _getUrl(uploadTask);
之后检索 url 以访问文件也很简单。
var url = await uploadTask.ref.getDownloadURL();
但是,这个 url 包含一个安全令牌,它基本上绕过了我设置的安全规则。任何拥有包含令牌的 url 的人都可以访问该文件。所以...我没有像这样检索 url,而是实现了这个:
var url = await _getUrl(uploadTask);
在哪里...
/*
* When we retrieve the download url using getDownloadURL then this include security token
* This makes the URL accessible for everybody, bypassing any security rule.
* I'm assuming that by removing the token this url becomes a URL only accessible for
* those who have access rights through the storage rules.
*/
static Future<String> _getUrl(firebase_storage.TaskSnapshot uploadTask) async {
var url = await uploadTask.ref.getDownloadURL();
var uri = Uri.parse(url);
var newMap = Map<String, dynamic>.from(uri.queryParameters)..removeWhere((k, v) => k == 'token');
var newUri = uri.replace(queryParameters: newMap);
var newUrl = newUri.toString();
return newUrl;
}
问题是:这是正确的方法吗?我很困惑为什么没有标准方法来检索 url 没有令牌。我也很困惑为什么没有其他人问这个问题。那么:我错过了什么?
I'm assuming that by removing the token this url becomes a URL only accessible for those who have access rights through the storage rules.
这个假设是不正确的。下载 URL 是不透明的 URL,您无法对其进行有意义的更改。按照您的方式更改它会使它无法正常工作。
如果您只希望经过身份验证的用户可以访问您的文件,您应该不为其生成下载URL。
如果您需要在未授予 public 访问权限的情况下与其他用户共享有关文件的信息,您可以存储其路径而不是下载 URL。然后,这些用户可以通过在该引用上构建 Reference
to it and then calling getData
or writeToFile
来访问该文件。与通过下载访问 URL 不同,通过引用访问通过您的规则受到保护。
根据 Frank van Puffelen 的回答,我最终实现了以下内容。 Ref 是对您的 firebase 存储图像的引用...
class FbStorageImage extends StatefulWidget {
final String ref;
const FbStorageImage({Key? key, required this.ref, }) : super(key: key);
@override
State<StatefulWidget> createState() {
return _FbStorageImageState();
}
}
class _FbStorageImageState extends State<FbStorageImage> {
Future<Uint8List?>? future;
@override
void initState() {
future = firebase_storage.FirebaseStorage.instance.ref(widget.ref).getData();
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Uint8List?>(
future: future,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data != null) {
return Image.memory(snapshot.data!);
} else {
return Image.asset("notfound.png");
}
}
return Center(child: DelayedCircularProgressIndicator());
});
}
}
我有这些要求:
- 我想上传文件到 firebase 存储。
- 我想存储这些文件的 URL 列表(在 firebase firestore 数据库中)。
- 我想使用存储规则限制查看这些文件。
将文件上传到 firebase 存储非常简单。
var uploadTask = await firebase_storage.FirebaseStorage.instance
.ref(ref)
.putFile(
file,
firebase_storage.SettableMetadata(
customMetadata: _customMetaData(ownerId, readAccess)));
var url = await _getUrl(uploadTask);
之后检索 url 以访问文件也很简单。
var url = await uploadTask.ref.getDownloadURL();
但是,这个 url 包含一个安全令牌,它基本上绕过了我设置的安全规则。任何拥有包含令牌的 url 的人都可以访问该文件。所以...我没有像这样检索 url,而是实现了这个:
var url = await _getUrl(uploadTask);
在哪里...
/*
* When we retrieve the download url using getDownloadURL then this include security token
* This makes the URL accessible for everybody, bypassing any security rule.
* I'm assuming that by removing the token this url becomes a URL only accessible for
* those who have access rights through the storage rules.
*/
static Future<String> _getUrl(firebase_storage.TaskSnapshot uploadTask) async {
var url = await uploadTask.ref.getDownloadURL();
var uri = Uri.parse(url);
var newMap = Map<String, dynamic>.from(uri.queryParameters)..removeWhere((k, v) => k == 'token');
var newUri = uri.replace(queryParameters: newMap);
var newUrl = newUri.toString();
return newUrl;
}
问题是:这是正确的方法吗?我很困惑为什么没有标准方法来检索 url 没有令牌。我也很困惑为什么没有其他人问这个问题。那么:我错过了什么?
I'm assuming that by removing the token this url becomes a URL only accessible for those who have access rights through the storage rules.
这个假设是不正确的。下载 URL 是不透明的 URL,您无法对其进行有意义的更改。按照您的方式更改它会使它无法正常工作。
如果您只希望经过身份验证的用户可以访问您的文件,您应该不为其生成下载URL。
如果您需要在未授予 public 访问权限的情况下与其他用户共享有关文件的信息,您可以存储其路径而不是下载 URL。然后,这些用户可以通过在该引用上构建 Reference
to it and then calling getData
or writeToFile
来访问该文件。与通过下载访问 URL 不同,通过引用访问通过您的规则受到保护。
根据 Frank van Puffelen 的回答,我最终实现了以下内容。 Ref 是对您的 firebase 存储图像的引用...
class FbStorageImage extends StatefulWidget {
final String ref;
const FbStorageImage({Key? key, required this.ref, }) : super(key: key);
@override
State<StatefulWidget> createState() {
return _FbStorageImageState();
}
}
class _FbStorageImageState extends State<FbStorageImage> {
Future<Uint8List?>? future;
@override
void initState() {
future = firebase_storage.FirebaseStorage.instance.ref(widget.ref).getData();
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Uint8List?>(
future: future,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data != null) {
return Image.memory(snapshot.data!);
} else {
return Image.asset("notfound.png");
}
}
return Center(child: DelayedCircularProgressIndicator());
});
}
}