Firebase 用户已通过身份验证,为什么上传到存储被拒绝?

Firebase user is authenticated, so why is uploading to storage denied?

在一个 react-native 项目中,我正在使用 both react-native-firebasefirebase sdk。 react-native-firebase 不允许使用 firebase 存储上传图像 blob,这就是我使用 vanilla Firebase javascript SDK 来完成这部分的原因。为了区别起见,在我的代码和这个 post 中,我将 firebase javascript sdk 标识为 'FIREBASE',将 react-native-firebase 标识为 'firebase'.

我必须初始化我的 firebase 应用程序(即使 react-native-firebase 不需要它的功能,firebase 需要),App.js 构造函数和导入:

 import * as React from 'react';
 import AppNavigation from './src/navigation';
 import { Provider } from 'react-redux';
 import { store, persistor } from './src/store/index.js';
 import firebase from 'firebase/app';
 import { PersistGate } from 'redux-persist/integration/react';
 export default class App extends React.Component {
   constructor (props) {
     super(props);
     const firebaseConfig = {
        apiKey: '{apiKey}',
        authDomain: 'project-ID.firebaseapp.com',
        databaseURL: 'https://project-ID.firebaseio.com',
        projectId: 'project-ID',
        storageBucket: 'project-ID.appspot.com',
        messagingSenderId: '9999999999'
     };
     if (!firebase.apps.length) {
        firebase.initializeApp(firebaseConfig);
     }
  }

我在一个动作中实现了 firebase FIREBASE(firebase 用于 auth/firestore,而 FIREBASE 用于存储):

import * as types from '../actions/types';
import RNFetchBlob from 'rn-fetch-blob';
import firebase from 'react-native-firebase';
import * as FIREBASE from 'firebase/app';
import 'firebase/storage';
import { Platform } from 'react-native';
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;

export const registerUser = (registration) => {
    const { email, pass, username, img } = registration;
    return (dispatch) => {
        dispatch({ type: types.REGISTER_USER });
        console.log('starting registration process...');
        // check username is unique
        firebase
            .firestore()
            .collection('users')
            .where('username', '==', username)
            .get()
            .then((querySnapshot) => {
                if (querySnapshot.empty !== true) {
                    // back to registration form
                    registrationFail(dispatch, 'Username already taken. Try again.');
                    console.log("Registrant's username already exists");
                } else {
                    console.log('Registrants username is unique');
                    // continue with registration
                    firebase
                        .auth()
                        .createUserWithEmailAndPassword(email, pass)
                        .then((userCredential) => {
                            // successful user creation, now authenticated
                            // write to img storage
                            uploadImg(dispatch, img, userCredential.user.uid)
                                .then((imgUrl) => {
                                    // on success, write to firestore
                                    uploadImgSuccess(dispatch, 'Profile image upload successful...');
                                    // write rest of data to firestore
                                        firebase
                                            .firestore()
                                            .collection('users')
                                            .add({
                                                createdAt: firebase.firestore.FieldValue.serverTimestamp(),
                                                username: email,
                                                uid: userCredential.user.uid,
                                                profileImg: imgUrl,
                                                email: email,
                                            })
                                            .catch((err) => {
                                                console.log('Registration failed. Error: ' + err.message);
                                                registrationFail(dispatch, err.message);
                                            });
                                    }
                                })
                                .catch((err) => {
                                    // Image Profile NOT Uploaded
                                    uploadImgFail(dispatch, err);
                                });
                        })
                        .catch((err) => {
                            // unsuccessful user creeation
                            registrationFail(dispatch, err.message);
                        });
                }
            })
            .catch((err) => registrationFail(dispatch, err.message));
    };
};
const uploadImg = async (dispatch, uri, uid, mime = 'image/png') => {
    console.log('Starting image upload...');
    dispatch({ type: types.UPLOAD_IMG, info: 'Uploading profile image...' });
    const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri;
    let uploadBlob = null;
    // let downloadPath = '';
    const imageRef = FIREBASE.storage().ref(uid).child('profileImg');
    fs
        .readFile(uploadUri, 'base64')
        .then((data) => {
            return Blob.build(data, { type: `${mime};BASE64` });
        })
        .then((blob) => {
            uploadBlob = blob;
            return imageRef.put(blob, { contentType: mime });
        })
        .then(() => {
            uploadBlob.close();
            return imageRef.getDownloadURL();
        })
        .then((url) => {
            console.log('Returning Download URL: ' + url);
            uploadImgSuccess(dispatch, 'Image upload successful...');
        })
        .catch((err) => {
            uploadImgFail(dispatch, 'Image  upload failed: ' + JSON.stringify(err));
        });
};

但是当我通过 uploadImg() 时,我得到一个错误:

{ 
  "code_": "storage/unauthorized", 
  "message":"Firebase Storage: User does not have permission to access 'someReference/someChild', 
  "serverResponse":{"Code":403, "message": "permission denied."}
}

这是 Firestore 规则:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
} 

这是存储规则:

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

我不明白发生了什么或为什么。用户在 react-native-firebase 的 createUserWithEmailAndPassword() 期间进行身份验证,甚至可以将数据上传到 Firestore。我唯一的猜测是,这可能与同时使用 firebase 和 FIREBASE 有关,或者与我使用 FIREBASE 设置 firebase 的方式有关。我在之前的测试项目中同时使用过这两个项目,并且它在分叉项目 rn-fetch-blobreact-native-fetch-blob 的维护版本)的帮助下成功运行,但是我没有安全规则到位 bc 测试, 所以...

有什么解决办法吗?

是的,您猜对了,您的 FIREBASE 实例不知道 firebase 正在完成的身份验证,因为 firebase 处理本机方面,而 FIREBASE 只是一个JS 的东西。所以这两个实例都有自己的生活和自己的前景,具有自己的属性来识别用户并提供授权。

要解决此问题,请尝试通过 vanilla JS SDK 授权用户或使用 rn-firebase 完成整个任务。 我建议使用 react-native-firebase,它对整个 firebase 堆栈有很好的支持。 https://rnfirebase.io/docs/v5.x.x/storage/reference/storage

编辑:

不应在移动应用程序中使用 Vanilla JS firebase SDK,尤其是当它是本机应用程序时,因为 firebase 会将客户端视为 Web 客户端,并且今后您将无法利用 firebase 中所有可能的移动设备,例如动态链接、推送通知和分析。

希望对您有所帮助!干杯!