You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter加载Firestore Bundles遇权限拒绝问题求助

问题分析与修复方案

核心问题定位

你遇到的Permission denied(403)错误来自Firebase Storage权限校验失败,同时代码中存在多处不一致和格式错误,具体如下:

1. 存储桶名称不匹配

Flutter代码中使用的桶是felix-3610.appspot.com,但Cloud Function上传bundle的目标桶是felix-366510.appspot.com,直接导致访问的对象不存在或权限校验对象错误。

2. Storage URL格式错误

你使用的https://storage.cloud.google.com/...是Cloud Storage的Web UI地址,无法被Firebase Storage SDK的refFromURL正确解析,应该使用Firebase标准格式的存储地址。

3. 权限规则不匹配

你的bundle文件路径为/music/bundles/epic_bundles.txt,对应Storage规则中match /music的allow read: if isIDN()条件,要求当前用户的auth token必须满足:

  • 已登录(request.auth.uid != null)
  • 携带Felix: true或HaD: true(isClient()/isServer())
  • 携带IDN: true(isIDN())
    如果用户未登录或token不符合上述要求,就会触发403错误。此外,Cloud Function中设置的public: true会被Storage规则覆盖,规则优先级高于对象公共权限。

4. Bundle与查询集合不匹配

Cloud Function生成的bundle基于Music_Relax集合,但Flutter代码加载后查询的是latest-epic集合,两者完全不对应,即使解决权限问题也无法获取数据。


分步修复方案

1. 统一存储桶名称

修改Flutter代码中的桶常量,与Cloud Function保持一致:

static const bucket = "felix-366510.appspot.com";

2. 修正Storage引用方式

替换错误的URL格式,改用Firebase SDK标准的路径构造:

// 移除原有的storage常量和path构造
final storageRef = FirebaseStorage.instance.ref(bucket).child("music/bundles/epic_bundles.txt");

3. 调整权限规则(测试+正式)

  • 临时测试:给bundle路径添加宽松规则,验证权限问题:
    rules_version = '2';
    service firebase.storage {
      match /b/{bucket}/o {
        // 新增bundle路径规则,放在最前面优先匹配
        match /music/bundles/{allPaths=**} {
          allow read: if request.auth != null; // 允许所有登录用户读取
        }
    
        // 保留原有其他规则...
      }
    }
    
  • 正式环境:确保用户登录后携带符合要求的auth token(IDN: true+Felix: true),再恢复原有严格规则。

4. 对齐Bundle与查询集合

修改Cloud Function中的查询集合,与Flutter代码保持一致:

const querySnapshot = await firestore.collection("latest-epic").where("status.state", "==", 1).get();

5. 优化Flutter加载代码

修复HTTP请求错误,简化异步逻辑,避免空指针:

Future<QuerySnapshot<Map<String, Object?>>> getEpic() async {
  try {
    const bucket = "felix-366510.appspot.com";
    final storageRef = FirebaseStorage.instance.ref(bucket).child("music/bundles/epic_bundles.txt");
    
    final url = await storageRef.getDownloadURL();
    final response = await http.get(Uri.parse(url));
    final buffer = response.bodyBytes; // 直接用bodyBytes避免编码问题

    final task = FirebaseFirestore.instance.loadBundle(buffer);
    await task.stream.drain(); // 等待bundle加载完成

    return await FirebaseFirestore.instance.collection("latest-epic").get(const GetOptions(source: Source.cache));
  } on FirebaseException catch (e) {
    log(e.code);
    rethrow; // 抛出错误避免返回空值
  }
}

内容的提问来源于stack exchange,提问作者Wege

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:05:39