用户已通过身份验证,但是:“Firebase 存储:用户无权访问“路径""出现错误 [英] User is AUTHENTICATED, but: "Firebase Storage: User does not have permission to access 'path'" error coming up

查看:64
本文介绍了用户已通过身份验证,但是:“Firebase 存储:用户无权访问“路径""出现错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在我的应用中实现了身份验证,并且在创建用户和身份验证方面没有问题.但是,现在我正在尝试将文件上传到 Firebase Storage,但它只会当我删除身份验证规则并公开访问时工作.如果我将默认规则保留为仅允许经过身份验证的用户访问(这正是我想要的),则会出现错误:Firebase Storage:用户无权访问profile-image/test.PNG". 我在 put 请求之前调用了一个方法来验证我的身份验证状态,并且我可以毫无问题地读/写 firestore 数据库,所以我确定我已经通过身份验证.

I've already implemented authentication in my app, and am having no problem with creating a user and authenticating. However, now I am trying to upload a file to Firebase Storage, but it will only work when I remove the auth rule and make access public. If I leave the default rules to only allow authenticated users to access (which is what I want), I get the error: Firebase Storage: User does not have permission to access 'profile-image/test.PNG'. I called a method to verify my auth state right before the put request, and I can read/write to the firestore database with no issues, so I know for sure I'm authenticated.

我是一个完整的 FNG,所以问题很可能是我做过/没做过的蠢事.如果相关,我正在使用 Angular.我还使用 Google Cloud Platform 激活了一个结算帐户,但这并没有什么区别.

I'm a complete FNG so there's a good chance the problem is something silly that I've done/not done. I'm using Angular if that is relevant. I also activated a billing account with Google Cloud Platform, but that didn't make a difference.

这是我的控制台日志,显示了我使用的引用、我尝试添加的文件(同样,当我公开访问时,这两个文件都可以正常工作)、来自 auth 状态调用的 uid,然后是错误:

Here's my console log showing the reference I used, the file I'm attempting to add (which again, both of those work just fine when I make access public), my uid from the auth state call, and then the error:

STARTING UPLOAD SERVICE                        upload.service.ts:26
FIREBASE STORAGE REFERENCE:                    upload.service.ts:27 
Reference {authWrapper: AuthWrapper, location: Location}
  authWrapper: AuthWrapper {bucket_: "my-app.appspot.com", deleted_: false, app_: FirebaseAppImpl, storageRefMaker_: ƒ, requestMaker_: ƒ, …}
bucket: (...)
fullPath: (...)
location: Location {bucket: "my-app.appspot.com", path_: "profile-image/test.PNG"}
name: (...)
parent: (...)
root: (...)
storage: (...)
__proto__: Object
                                                 upload.service.ts:28 
FILE CONTENTS:
                                                 upload.service.ts:29 
File(286831) {name: "test.PNG", lastModified: 1542480795011, lastModifiedDate: Sat Nov 17 2018 13:53:15 GMT-0500 (Eastern Standard Time), webkitRelativePath: "", size: 286831, …}
                                                 upload.service.ts:24 
USER AUTHENTICATED: Er6sWsDvEjM69WBAKxQffcbdPZG2
POST https://firebasestorage.googleapis.com/v0/b/{my-app-name}/o?name=profile-image%2Ftest.PNG 403
                                                 upload.service.ts:33  
FirebaseStorageError {code_: "storage/unauthorized", message_: "Firebase Storage: User does not have permission to access 'profile-image/test.PNG'.", 
serverResponse_: "{↵  "error": {↵    "code": 403,↵    "message": "Pe…n denied. Could not perform this operation"↵  }↵}", name_: "FirebaseError"}
code: (...)
code_: "storage/unauthorized"
message: (...)
message_: "Firebase Storage: User does not have permission to access 'profile-image/test.PNG'."
name: (...)
name_: "FirebaseError"
serverResponse: (...)
serverResponse_: "{↵  "error": {↵    "code": 403,↵    "message": "Permission denied. Could not perform this operation"↵  }↵}"
__proto__: Object 

Firebase 存储规则

Firebase Storage Rules

service firebase.storage {
 match /b/my-app.appspot.com/o {
  match /{allPaths=**} {
   allow read, write: if request.auth != null;
  }
 }
}  

(我也试过 request.auth.uid != null 但这并没有什么区别.)

(I also tried request.auth.uid != null but that didn't make a difference.)

我的上传服务:

import { Injectable } from '@angular/core';
import * as firebase from 'firebase/app';
import 'firebase/storage';
import { AuthService } from '../services/auth.service';


@Injectable({
  providedIn: 'root'
})
export class UploadService {

  constructor(
    private authService: AuthService
  ) { }

  pushUpload(uploadFile: File) {
    console.log("STARTING UPLOAD SERVICE")
    var storage = firebase.storage();
    var storageRef = storage.ref();
    var profileRef = storageRef.child('profile-image');
    var docRef = profileRef.child(uploadFile.name);

    this.authService.getAuthState().subscribe(auth => {
      console.log("USER AUTHENTICATED: " + auth.uid);
    })
    console.log("FIREBASE STORAGE REFERENCE:")
    console.log(docRef);
    console.log("FILE CONTENTS:");
    console.log(uploadFile);
    docRef.put(uploadFile).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    });
  }
}

environment.ts 中的 Firebase 配置:

Firebase config in environment.ts:

import * as fb from 'firebase/app';

// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.

export const environment = {
  production: false,
  firebase: {
    apiKey: "{my-api-key}",
    authDomain: "my-app.firebaseapp.com",
    databaseURL: "my-app.firebaseio.com",
    projectId: "my-app",
    storageBucket: "gs://my-app.appspot.com",
    messagingSenderId: "####"
  }
};

fb.initializeApp(environment.firebase);

我在控制台日志中用 generic 替换了一些识别信息 &环境.ts 文件.我还应该提到,在我添加 fb.initializeApp(environment.firebase); 之前,身份验证对我来说工作得很好,但是一旦我尝试发出上传请求,我就会收到没有这条线的错误.

I replaced some of the identifying information with generic in the console log & environment.ts file. I should also mention that authentication was working just fine for me before I added fb.initializeApp(environment.firebase); but I was getting an error without this line once I tried to make an upload request.

非常感谢您提供的任何建议 &如果我需要提供更多信息,请告诉我!

Thanks so much in advance for any advice you may have & if I should provide any more info, please let me know!

推荐答案

事实证明,我使用的是 Angular 确实很重要.我需要像这样将 AngularFireStorage 添加到我的 app.module.ts 中:

As it turns out, it did matter that I was using Angular. I needed to add AngularFireStorage to my app.module.ts like so:

import { AngularFireStorage } from '@angular/fire/storage'; 

@NgModule({
....
providers: [..., AngularFireStorage]

然后还必须导入到我的uploads.component.ts:

and then also had to import to my uploads.component.ts:

import { AngularFireStorage, AngularFireUploadTask } from '@angular/fire/storage';

然后我完全废弃了我的 UploadService 并抓住了这个人教程的部分内容:https://angularfirebase.com/lessons/firebase-storage-with-angularfire-dropzone-file-uploader/ 它使用 AngularFireUploadTask 和一些 Observables 来非常轻松地完成整个上传过程.所以这是我最终在我的 uploads.component.ts 中得到的方法:

and then I completely scrapped my UploadService and snagged parts of this guy's tutorial: https://angularfirebase.com/lessons/firebase-storage-with-angularfire-dropzone-file-uploader/ which uses an AngularFireUploadTask and some Observables to accomplish the entire upload process really easily. So here's the resulting method I ended up with in my uploads.component.ts:

import { Component, OnInit, Input } from '@angular/core';
import { AngularFireStorage, AngularFireUploadTask } from '@angular/fire/storage';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-uploads',
  templateUrl: './uploads.component.html',
  styleUrls: ['./uploads.component.css']
})
export class UploadsComponent implements OnInit {
  @Input() uploadFolder: string;  //the folder to save this particular upload to in the Storage Bucket   
  selectedFile: File;
  task: AngularFireUploadTask;  // Main task 
  percentage: Observable<number>;  // Progress monitoring
  snapshot: Observable<any>;// Progress monitoring


  constructor(
    private storage: AngularFireStorage
    ) { }

  ngOnInit() {}

  .
  .
  .

  startUpload() {  
    if (this.selectedFile.type.split('/')[0] !== 'image') { 
      console.error('unsupported file type :( ')
      return;
    } else {
      const path = this.uploadFolder + "/" + this.userID;
      // The main task
      this.task = this.storage.upload(path, this.selectedFile)
      // Progress monitoring
      this.percentage = this.task.percentageChanges();
      this.percentage.subscribe(data => {
        // Do something with my progress
      })
      this.snapshot = this.task.snapshotChanges();
      this.snapshot.subscribe(data => {
        // Do something with my progress
      })
      // The file's download URL
      this.task.then(snapshot => {
        console.log("UPLOAD SUCCESS!");
        snapshot.ref.getDownloadURL().then(url => {
          console.log(url);
          //Do something with my new file's url
        })
      }, 
      (err) => {
        //Do something about errors...  
      });
    }
  }
}

并且我从我的 environment.ts 文件中删除了 firebase 初始化,所以很明显 Angular 正在某个地方为我初始化 firebase,因为这是不必要的.我相信这就是为什么 Firestore 显示我已通过身份验证的原因(因为我初始化了用于登录的 firebase 和通过 AngularFire 的 firestore),但 Firebase Storage 显示我未通过身份验证(因为我在我的 environment.ts 文件,这是我没有像我应该使用的那样使用 AngularFireStorage 的解决方法).所以基本上这一切都归结为一个事实,即我没有(不)完全理解 Angular 到底在为我做什么.呃...我真的希望这能在某个时候帮助某人...

And I removed the firebase initialization from my environment.ts file, so clearly Angular is initializing firebase for me somewhere since this is unnecessary. I believe this is why there was a discrepancy between why Firestore showed I was authenticated (because I initialized firebase for logging in and firestore through AngularFire), but Firebase Storage showed I was NOT authenticated (because I initialized firebase for THAT separately in my environment.ts file, which was my work-around for not utilizing AngularFireStorage like I should have). So basically this all boils down to the fact that I didn't(don't) fully understand what exactly Angular was doing for me. ugh...I really hope this helps someone at some point...

这篇关于用户已通过身份验证,但是:“Firebase 存储:用户无权访问“路径""出现错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆