使用Firebase Admin在Python生成符合Storage规则的永久下载URL
问题描述
我正在开发一款读取Firestore数据库和Firebase Storage的Flutter应用,Firebase Storage读取规则设置为仅允许已认证用户访问。我还有一个Python脚本,负责将内容上传至Firebase Storage并更新Firestore中的相关文件URL。
上传代码片段:
def _upload_file(self, file_path: str, storage_path: str) -> str: blob = self.bucket.blob(storage_path) blob.upload_from_filename(file_path) return blob.public_url
但通过该代码生成的URL会返回403错误,即便是应用的已认证用户访问,甚至将Storage规则设置为允许任意读写时也是如此。
需求与尝试过的方法
我需要为上传的文件生成可存储在Firestore中、供Flutter应用访问的URL。以下是尝试过的方法及问题:
blob.public_url:即便用户已认证,Flutter中访问仍返回403错误。generate_signed_url():URL会在7天后过期,不符合需求。blob.make_public():Flutter中可正常访问,但会绕过安全规则,存在安全风险(即使规则设置为仅允许已认证用户读取,该URL也能被任意访问)。
补充信息
之前开发的Flutter应用中,直接在应用内上传的Dart代码可生成正确URL:
Future<String> uploadUserImage(File image, String uid) async { final String fileName = uid + ".jpg"; final ref = _storage.ref().child(StorageCollections.userImages).child(fileName); await ref.putFile(image); return await ref.getDownloadURL(); } // 生成的URL示例:https://firebasestorage.googleapis.com/v0/b/xxxxx/o/userImages%xxxxx.jpg?alt=media&token=xxxxxx
但无法在Python中实现相同效果。
核心问题
如何在文件上传后,使用firebase_admin模块(或其他方法)获取符合Storage规则且不会过期的正确URL?
解决方案
方法1:通过元数据设置永久下载令牌(推荐)
Firebase允许为Storage对象添加永久下载令牌,生成的URL格式和Flutter中getDownloadURL()返回的一致,且受安全规则约束。修改Python上传代码即可实现:
import firebase_admin from firebase_admin import storage import uuid import urllib.parse # 初始化Firebase Admin(确保已配置服务账号密钥) if not firebase_admin._apps: cred = firebase_admin.credentials.Certificate('path/to/service-account-key.json') firebase_admin.initialize_app(cred, { 'storageBucket': 'your-bucket-name.appspot.com' }) def _upload_file(self, file_path: str, storage_path: str) -> str: bucket = storage.bucket() blob = bucket.blob(storage_path) blob.upload_from_filename(file_path) # 生成并设置永久下载令牌 download_token = uuid.uuid4().hex blob.metadata = {'firebaseStorageDownloadTokens': download_token} blob.patch() # 提交元数据修改 # 构造符合规则的下载URL base_url = f"https://firebasestorage.googleapis.com/v0/b/{bucket.name}/o/" encoded_path = urllib.parse.quote(blob.name) return f"{base_url}{encoded_path}?alt=media&token={download_token}"
方法2:调用Firebase Storage REST API获取URL
如果元数据方法不生效,可通过Admin SDK获取权限令牌后调用REST API:
import requests import urllib.parse from firebase_admin import auth def get_download_url(blob): # 获取Admin服务账号的ID令牌 id_token = auth.create_custom_token('service-account-uid').decode('utf-8') # 构造API请求 api_url = f"https://firebasestorage.googleapis.com/v0/b/{blob.bucket.name}/o/{urllib.parse.quote(blob.name)}" headers = {'Authorization': f'Bearer {id_token}'} response = requests.get(api_url, headers=headers) if response.status_code == 200: token = response.json()['downloadTokens'] return f"{api_url}?alt=media&token={token}" else: raise Exception(f"获取URL失败:{response.text}")
关键说明
- 生成的URL受Storage安全规则约束,只有已认证用户可访问,符合安全要求。
- 下载令牌永久有效,除非手动修改blob元数据删除令牌。
- 确保服务账号拥有
storage.objects.update权限,否则无法修改元数据。
内容的提问来源于stack exchange,提问作者Cle
相关产品推荐
相关产品推荐

