用户已登录但无法通过 AngularFire 访问 Firebase 存储

User is logged in yet cannot access Firebase Storage through AngularFire

我正在通过 angularfire 使用 Angular 和 Firebase 开发一个网络应用程序。我有一个为用户处理身份验证过程的服务,名为 HandleAuthService。我想允许用户上传他们自己的头像。我将个人资料图片存储在 Firebase 存储中的唯一文件路径下。他们的图片存放的文件路径在: UID/displayPicture/.

当用户上传图片时,它会出现在他们唯一路径下的 Firebase 存储中。但是,当我尝试下载图片以便显示时,我 运行 遇到 403 错误,它声称用户没有读取或写入权限。

错误

ERROR FirebaseError: Firebase Storage: User does not have permission to access 'USER_ID/displayPicture.jpg'. (storage/unauthorized)
{
  "error": {
    "code": 403,
    "message": "Permission denied. Please enable Firebase Storage for your bucket by visiting 
the Storage tab in the Firebase Console and ensure 
that you have sufficient permission to 
properly provision resources."
  }
}

这是我的存储规则(我没有更改):

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

我尝试删除 if request.auth !=null; 但它仍然产生相同的错误。

以下是 HandleAuthService 代码的片段:

constructor(private fireAuth: AngularFireAuth, private ngZone: NgZone, private router: Router) { 
    //I create an observable for other components to subscribe to in order to get
    //key information such as the uid 
    this.currentUser$ = this.fireAuth.authState.pipe(
      take(1),
      map(user => {
        if (user) {
          return {uid: user.uid, email:user.email, displayName:user.displayName}
        } else {
          return null;
        }
      })
    );
}

  //to login at the very beginning, the users may do so through google
  googleLogin(provider:any) {
    return this.fireAuth.signInWithPopup(provider)
    .then((result)=> {
      this.ngZone.run(() => {
        this.router.navigate(['data']);
      });
      this.setUser(result.user);
    })
    .catch((error) => {
      console.log(error);
    })
  }

然后,在每个组件中,我订阅 this.currentUser$ 以访问用户的 authState 数据。这一直适用于所有其他组件。

在我显示头像的组件中,picture.component.ts:

constructor(private handleAuth:HandleAuthService, private storage: AngularFireStorage, private crowboxService:CrowboxdbService) { }

//in this function I try to get the profile picture from the Firebase Storage 
ngOnInit(): void {
    //Subscribe to the user auth state observable and wait 
    //to get the UID to proceed - then get the user's profile picture to be displayed
    this.handleAuth.currentUser$
    .subscribe(user => {
      this.userId = user.uid;
      this.getProfilePicture();
    });  
  }

//the function to upload the profile picture - invoked by the click of a button
uploadFile(event:any) {
    const file = event.target.files[0];
    this.filePath = `${this.userId}/displayPicture`;
    const task = this.storage.upload(this.filePath, file);
  }

//the function to get the profile picture
getProfilePicture() {
    const ref = this.storage.ref(`${this.userId}/displayPicture.jpg`);
    this.profileUrl = ref.getDownloadURL();
  }

picture.component.ts的HTML观点:

<div id="imageContainer">
    IMAGE GOES HERE
    <img alt="Profile Picture" [src]="profileUrl | async" />     
    <div>
        <input type="file" (change)="uploadFile($event)">
    </div>
</div>

如果用户可以上传图片,为什么我检索不到图片?如何确保用户已登录?

我还想补充一点,我也设置了路由守卫:

const routes: Routes = [
  { path:'', redirectTo:'/home', pathMatch:'full' },
  { path:'home', component:HomeComponent},
  { path:'data', component:DataComponent, canActivate: [AngularFireAuthGuard] },
  { path:'troubleshoot', component:TroubleshootComponent, canActivate: [AngularFireAuthGuard] },
  { path:'profile', component:ProfileComponent, canActivate: [AngularFireAuthGuard] },  
];

问题在于 URL 的检索方式。这是根据 AngularFire Documentation 的正确方法:

picture.component.ts

uploadFile(event:any) {
    const file = event.target.files[0];
    this.filePath = `/Users/${this.userId}/profilePicture`;
    const fileRef = this.storage.ref(this.filePath);
    const task = this.storage.upload(this.filePath, file);


    this.$taskSub = task.snapshotChanges().pipe(
      finalize(() => {
        //Get the download url of the photo that has been stored
        //in the storage
        this.downloadURL = fileRef.getDownloadURL();
        
        this.$downloadURLSub = this.downloadURL.subscribe(result => {
          this.profileUrl = result;
        })
      }))
    .subscribe();
  }

在这段代码中,我在 Firebase 项目中订阅了任务的更改,并从可观察的任务中检索下载 URL。 URL 现在可用于检索图像,如下所示。

picture.component.html

<img src="{{profileUrl}}" alt="Profile Picture" class="imageContainer">