简体   繁体   English

应用程序中的Firebase(存储)权限被拒绝,但模拟器中没有?

[英]Firebase (Storage) permission denied in app but not in simulator?

My write access is denied when trying to upload new photo: 尝试上传新照片时,我的写入权限被拒绝:

User does not have permission to access this object. 用户无权访问此对象。

My security rules: 我的安全规则:

service firebase.storage {
  match /b/{bucket}/o {
    match /user_photo/{imageid} {
      allow read, write: if request.auth != null && imageid==request.auth.uid;
    }
  }
}

The storage reference of the image I want to "update" (upload new photo with same name which is uid, below uid is changed for simplicity) 我想要“更新”的图像的存储参考(上传具有相同名称的新照片,uid,uid以下更改为了简单)

/user_photo/123456

123456 is the uid of the current authorized user in my app. 123456是我的应用程序中当前授权用户的uid。

At the method reference.putfile(uri) , reference is: 在方法reference.putfile(uri) ,引用是:

gs://my-app-name.appspot.com/user_photo/123456

uri is: uri是:

content://com.android.providers.media.documents/document/image%3A38830

Photo upload process in my app is working fine (tested with rules set so that all reads and writes are accepted). 我的应用程序中的照片上传过程工作正常(使用规则进行测试,以便接受所有读取和写入)。 With security rules, in the console simulator, if I check authenticated checkbox && write 123456 as userid, the simulator allows all operations. 使用安全规则,在控制台模拟器中,如果我检查经过身份验证的复选框&&将123456写为userid,则模拟器允许所有操作。 But from my app, I get the error I posted above. 但是从我的应用程序中,我得到了上面发布的错误。

Any suggestions on what might cause this? 有什么可能导致这个的建议吗?

EDIT1: EDIT1:

The whole "operation" is to upload a new photo with firebaseuser uid as the photoname, in the folder "/user_photo", then update the photourl in firebaseuser to the newly added photo. 整个“操作”是使用firebaseuser uid作为光子名称上传新照片,在文件夹“/ user_photo”中,然后将firebaseuser中的photourl更新为新添加的照片。

Before changing the security rules, this process "worked" and I could upload the photo accordingly, and get download url from firebaseuser.getPhotoUrl(), and download correct photo. 在更改安全规则之前,此过程“有效”,我可以相应地上传照片,并从firebaseuser.getPhotoUrl()获取下载URL,并下载正确的照片。 After I added the new rules, I get denied from application (and not from simulator in console)- 添加新规则后,我被应用程序拒绝(而不是来自控制台中的模拟器) -

MyInteractor.class: MyInteractor.class:

public Completable changeProfilePhoto(Uri uri){
        return authRepo.getCurrentUser()
                .take(1)
                .flatMapCompletable(firebaseUser -> storageRepo.uploadPhoto(firebaseUser.getUid(), uri)
                        .flatMap(taskSnapshot -> storageRepo.getDownloadUrl(taskSnapshot.getMetadata().getReference()))
                        .flatMapCompletable(uploadedUri -> authRepo.changeUserPhoto(firebaseUser, uploadedUri)))
                .observeOn(AndroidSchedulers.mainThread());
    }

FirebaseAuthRepository (authRepo above) methods: FirebaseAuthRepository(上面的authRepo)方法:

@Override
public Observable<FirebaseUser> getCurrentUser() {
    return FirebaseAuthWrapper.observeUserAuthState(firebaseAuth)
            .map(FirebaseAuth::getCurrentUser)
            .switchIfEmpty(observer -> {
                observer.onError(new RxWrapperNullException(RxWrapperNullException.NO_CURRENT_USER));
            })
            .subscribeOn(Schedulers.io());
}

@Override
public Completable changeUserPhoto(FirebaseUser firebaseUser, Uri uri){
    UserProfileChangeRequest request = new UserProfileChangeRequest.Builder()
            .setPhotoUri(uri)
            .build();
    return FirebaseUserWrapper.updateUserProfile(firebaseUser,request);
}

FirebaseStorageRepository (storageRepo above) methods: FirebaseStorageRepository(上面的storageRepo)方法:

@Override
public Single<UploadTask.TaskSnapshot> uploadPhoto(String user, Uri uri) {
    StorageReference thisRef = userPhoto.child(String.format("/%S", user));
    return FirebaseStorageWrapper.putFile(thisRef, uri)
            .subscribeOn(Schedulers.io());
}

@Override
public Single<Uri> getDownloadUrl(StorageReference reference) {
    return FirebaseStorageWrapper.getDownloadUrl(reference)
            .toSingle()
            .subscribeOn(Schedulers.io());
}

From my Viewmodel.class, I call the myInteractor.changeProfilePhoto(uri) where uri is path to image on the android device as chosen by user from intent 从我的Viewmodel.class,我调用myInteractor.changeProfilePhoto(uri),其中uri是android设备上的图像路径,由用户从意图中选择

EDIT 2: 编辑2:

I noticed I forgot to add wrapper class methods, which may be of importance: 我注意到我忘了添加包装类方法,这可能很重要:

FirebaseStorageWrapper.class: FirebaseStorageWrapper.class:

public static Single<UploadTask.TaskSnapshot> putFile(StorageReference reference, Uri uri){
    return Single.create(emitter -> {
        StorageTask<UploadTask.TaskSnapshot> task = reference.putFile(uri)
                .addOnSuccessListener(emitter::onSuccess)
                .addOnFailureListener(e -> {
                    if(!emitter.isDisposed()){
                        emitter.onError(e);
                    }
        });
        emitter.setCancellable(task::cancel);
    });
}

public static Maybe<Uri> getDownloadUrl(StorageReference ref) {
    return Maybe.create(emitter -> MaybeTask.assign(emitter, ref.getDownloadUrl()));
}

FirebaseUserWrapper.class: FirebaseUserWrapper.class:

public static Completable updateUserProfile(FirebaseUser firebaseUser, UserProfileChangeRequest request){
    return Completable.create(emitter -> CompletableTask.assign(emitter, firebaseUser.updateProfile(request)));
}

assign() method in both CompletableTask and MaybeTask just sets listeners to Task, and in each listener when invoked by events, sends data to the emitter for it to emit. CompletableTask和MaybeTask中的assign()方法只是将侦听器设置为Task,并且在每个侦听器中由事件调用时,将数据发送到发射器以使其发出。

EDIT 3: 编辑3:

FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
StorageReference storageReference = FirebaseStorage.getInstance().getReference().child("/user_photo").child(String.format("/%S", firebaseUser.getUid()))
storageReference.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        taskSnapshot.getMetadata().getReference().getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
            @Override
            public void onSuccess(Uri newUri) {
                UserProfileChangeRequest request = new UserProfileChangeRequest.Builder()
                        .setPhotoUri(newUri)
                        .build();
                firebaseUser.updateProfile(request).addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        //if it gets here it means operation was successful
                    }
                }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {

                    }
                });
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
            }
        });

    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        //it fails here == storageReference.putFile(uri)
    }
});

Add Storage Rules... in your firebase "Storage Rules" 在您的firebase“存储规则”中添加存储规则....

Add this : allow read, write; 添加 :允许读,写;

and remove this : if request.auth != null && imageid==request.auth.uid; 并删除此 :如果request.auth!= null && imageid == request.auth.uid;

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM