Reputation: 1636
I have these requirements:
Uploading a file to firebase storage is straightforward.
var uploadTask = await firebase_storage.FirebaseStorage.instance
.ref(ref)
.putFile(
file,
firebase_storage.SettableMetadata(
customMetadata: _customMetaData(ownerId, readAccess)));
var url = await _getUrl(uploadTask);
Retrieving the url to access the file afterwards is trivial as well.
var url = await uploadTask.ref.getDownloadURL();
However, this url includes a security token, which basically bypasses the security rules which I have setup. Anyone with the url which includes the token has access to the file. So... instead of retrieving the url as such, I've implemented this one:
var url = await _getUrl(uploadTask);
Where...
/*
* 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;
}
The question is: is this the right approach? I'm puzzled why there wouldn't be a standard method to retrieve the url without the token. I'm also puzzled why nobody else is asking this question. So: what am I missing?
Upvotes: 0
Views: 1132
Reputation: 1636
Based on Frank van Puffelen's answer, I ended up implementing the below. Ref is the reference to your firebase storage image...
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());
});
}
}
Upvotes: 0
Reputation: 599716
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.
This assumption is incorrect. The download URL is an opaque URL, and you can't meaningfully change it. Changing it the way you did leaves it non-functional.
If you only want authenticated users to have access to your file, you should not generate a download URL for it.
If you need to share information about the file with other users without granting public access, you can store its path instead of the download URL. Those users can then have access the file by constructing a Reference
to it and then calling getData
or writeToFile
on that reference. Unlike access through a download URL, access through a reference is secured through your rules.
Upvotes: 2