已登录用户通过AngularFire访问Firebase Storage报403无权错误
问题根因分析
- 最核心的错误是上传和读取的文件路径不匹配:上传逻辑里的路径是
${this.userId}/displayPicture,没有.jpg后缀,文件实际存储的名称就是不带后缀的displayPicture;但读取逻辑里的路径是${this.userId}/displayPicture.jpg,多了后缀,访问的是不存在的资源。Firebase Storage出于安全考虑,对不存在的资源也会返回403错误而非404,避免泄露文件存在性。 - 潜在问题:你给
currentUser$加了take(1)操作符,只会取登录状态的第一个发射值,如果组件初始化时Firebase Auth还没完成登录校验,第一次发射的是null,直接取user.uid会报错,也可能导致后续请求不带认证信息。 - 规则排查:如果你移除了auth校验规则还是报错,大概率是修改完Storage规则后没有点击控制台的「发布」按钮,规则并未实际生效。
修复方案
- 统一文件路径
修改上传或读取逻辑保持文件名一致即可,比如修改上传逻辑补充后缀:
uploadFile(event:any) { const file = event.target.files[0]; // 统一加.jpg后缀,也可根据上传文件实际后缀动态取值 this.filePath = `${this.userId}/displayPicture.jpg`; const task = this.storage.upload(this.filePath, file); }
或者修改读取逻辑去掉后缀:
getProfilePicture() { const ref = this.storage.ref(`${this.userId}/displayPicture`); this.profileUrl = ref.getDownloadURL(); }
- 优化登录状态监听逻辑
移除take(1)操作符,避免错过后续登录状态更新,同时补充非空判断避免空值报错:
// HandleAuthService中修改currentUser$定义 this.currentUser$ = this.fireAuth.authState.pipe( map(user => { if (user) { return {uid: user.uid, email:user.email, displayName:user.displayName} } else { return null; } }) ); // 组件中订阅时补充非空判断 this.handleAuth.currentUser$ .subscribe(user => { if(user) { this.userId = user.uid; this.getProfilePicture(); } });
- 确认Storage规则生效
修改规则后必须点击Firebase控制台Storage页面规则标签下的「发布」按钮,等待1-2分钟规则生效后再测试。建议后续优化规则限制用户只能访问自己路径下的文件,安全性更高:
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /{userId}/{allPaths=**} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
确认用户登录状态的方法
- 直接订阅
AngularFireAuth的authStateobservable,发射非null值即为已登录:
this.fireAuth.authState.subscribe(user => { console.log('是否登录:', !!user); if(user) console.log('登录用户UID:', user.uid); })
- 调用
this.fireAuth.currentUser方法,返回非null值即为已登录,该方法返回Promise:
async checkLoginStatus() { const user = await this.fireAuth.currentUser; console.log('当前登录用户:', user); }
- 可在浏览器控制台Application标签下,查看对应站点的IndexedDB存储,是否存在Firebase Auth相关的持久化凭证,也可以确认登录状态。
内容的提问来源于stack exchange,提问作者Hamza Qureshi
相关产品推荐
相关产品推荐

