Мой доступ к записи запрещен при попытке загрузить новое фото:
У пользователя нет прав доступа к этому объекту.
Мои правила безопасности:
service firebase.storage {
match /b/{bucket}/o {
match /user_photo/{imageid} {
allow read, write: if request.auth != null && imageid==request.auth.uid;
}
}
}
Ссылка на хранилище изображения, которое я хочу "обновить" (загрузить новую фотографию с тем же именем, которое является uid, ниже uid изменено для простоты)
/user_photo/123456
123456
- это идентификатор текущего авторизованного пользователя в моем приложении.
При методе reference.putfile(uri)
ссылка:
gs://my-app-name.appspot.com/user_photo/123456
URI:
content://com.android.providers.media.documents/document/image%3A38830
Процесс загрузки фотографий в моем приложении работает нормально (проверено с правилами, установленными так, что все чтения и записи принимаются). С правилами безопасности, в симуляторе консоли, если я установлю флажок с проверкой подлинности && напишите 123456 как идентификатор пользователя, симулятор разрешит все операции. Но из моего приложения я получаю сообщение об ошибке, которое я разместил выше.
Любые предложения о том, что может вызвать это?
EDIT1:
Вся «операция» состоит в том, чтобы загрузить новую фотографию с идентификатором пользователя firebaseuser в качестве фотоизображения в папку «/ user_photo», а затем обновить фотолабораторию в firebaseuser до вновь добавленной фотографии.
Перед изменением правил безопасности этот процесс "работал", и я мог соответственно загрузить фотографию и получить URL-адрес для загрузки из firebaseuser.getPhotoUrl () и загрузить правильную фотографию. После добавления новых правил мне отказывают в приложении (а не в симуляторе в консоли) -
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):
@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 (хранилище приведено выше):
@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());
}
Из моего Viewmodel.class я вызываю myInteractor.changeProfilePhoto (uri), где uri - это путь к изображению на устройстве Android, выбранный пользователем из намерение
РЕДАКТИРОВАТЬ 2:
Я заметил, что забыл добавить методы класса-оболочки, что может иметь важное значение:
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:
public static Completable updateUserProfile(FirebaseUser firebaseUser, UserProfileChangeRequest request){
return Completable.create(emitter -> CompletableTask.assign(emitter, firebaseUser.updateProfile(request)));
}
Метод assign () в CompletableTask и MaybeTask просто устанавливает прослушиватели в Task, а в каждом прослушивателе при вызове по событиям отправляет данные эмиттеру для его отправки.
РЕДАКТИРОВАТЬ 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)
}
});