Firestore отсутствует или недостаточно прав и React Native - PullRequest
0 голосов
/ 04 августа 2020

Я новичок в Firebase и React Native. Когда я добавляю в приложение аутентификацию по электронной почте и обновляю правила аутентификации, я получаю сообщение об ошибке Отсутствуют или недостаточно привилегий .

Я получаю сообщение об ошибке при попытке записи в Firestore в функции componentDidMount в Экран 1.

Я добавил следующие правила для своего приложения.

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

Если я перейду на allow read, write: if true; , все будет работать нормально. Однако это не то, что мне нужно для производственного приложения, которое я планирую развернуть.

Я проверил свое приложение, вытащив текущего пользователя, и похоже, что пользователь вошел в систему и прошел проверку подлинности.

И я получаю сообщение об ошибке аутентификации: [FirebaseError: Отсутствуют или недостаточны разрешения.], Когда я пытаюсь сделать следующее:

Config. js

import Firebase from "firebase";

// Web App Firebase Configuration
var firebaseConfig = {
    apiKey: "pretendapikeytoprotect",
    authDomain: "pretendapp.firebaseapp.com",
    databaseURL: "https://pretendapp.firebaseio.com",
    projectId: "pretendapp",
    storageBucket: "pretendapp.appspot.com",
    messagingSenderId: "messengerSenderIDnumbers",
    appId: "appIDNumber",
    measurementId: "measureIDnumberiD"
  };

  const app = Firebase.initializeApp(firebaseConfig);

  // Initialize Cloud Firestore through firebase
  export const db = app.firestore();
  db.settings({experimentalForceLongPolling: true});

App. js

/**
 * @format
 * @flow strict-local
 */
import 'react-native-gesture-handler';
import React, {Component} from 'react';
import Providers from './src/navigation';

import {
  Alert,
  I18nManager,
  YellowBox
} from 'react-native';

//Ignore Warning about Setting a Timer/No known fix at this time.
YellowBox.ignoreWarnings(['Setting a timer']);

type Props = {};

export default class App extends React.Component<Props, State> {

    constructor(props: Props) {
      super(props);
      
    }

    componentWillUnmount() {
      //willMountFunctions
    }

    componentDidMount() {
    //DidMountFunctions    
    }

  render() {
    return (
      <Providers />
    )
  }
}

Провайдеры - /src/navigation/index.js

import React from 'react';
import { AuthProvider } from './AuthProvider';
import Routes from './Routes';

export default function Providers()  {
    return (
    <AuthProvider>
      <Routes />
    </AuthProvider>
  );
}

Маршруты. js

import React, { useContext, useState, useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import auth from '@react-native-firebase/auth';
import AuthStack from './AuthStack';
import HomeStack from './HomeStack';
import { AuthContext } from './AuthProvider';
import Loading from '../components/Loading';

export default function Routes() {

    const { user, setUser } = useContext(AuthContext);
    const [loading, setLoading] = useState(true);
    const [initializing, setInitializing] = useState(true);
    
    // Handle user state changes
    function onAuthStateChanged(user) {
      setUser(user);
      if (initializing) setInitializing(false);
      setLoading(false);

      if (user) {
        console.log('user is logged');
      }
    }

    useEffect(() => {
      const subscriber = auth().onAuthStateChanged(onAuthStateChanged);
      return subscriber; // unsubscribe on unmount
    }, []);

    if (loading) {
      return <Loading />;
    }

    return (
      <NavigationContainer>
        {user ? <HomeStack /> : <AuthStack />}
      </NavigationContainer>
    );
  }

HomeStack. js

import React  from 'react';
import { createStackNavigator } from '@react-navigation/stack';

//Import Components
import HomeScreen from '../screens/HomeScreen';
import Screen1 from '../screens/Screen1';

const Stack = createStackNavigator();

export default function HomeStack() {

  return (
    <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home"
                  component = {HomeScreen}
                  options={{ title: 'Home Screen' }} />
        <Stack.Screen name="Screen1" 
                  component={Screen1}
                  options={{ title: 'Screen 1' }}  />
    </Stack.Navigator>
  );
}

Файл-помощник (helpers. js)

const RNFS = require('react-native-fs');
import storage from '@react-native-firebase/storage';
import firestore from '@react-native-firebase/firestore';
import { db } from '../config';
import { Platform } from 'react-native';
import { currentUser } from '../navigation/AuthProvider';
import auth from '@react-native-firebase/auth';

// removed other functions not relevant to question //

 export const WriteSessionData = async (sessionID) => {
    
      console.log("Write Session current User Logged in ", currentUser.uid);
      console.log("Current Session User in Write Session ", auth().currentUser)

      const session = db.collection('sessions').doc(sessionID);
      
      await session.set({
        name: '',
        email: '',
        timedate : Date.now(),})
        .then(() => {
          console.log("Session Data Added to Database");
        }).catch((err) => {
      console.log("Error in Writing to Database ", "User Logged in as: ", currentUser.uid, err);
    });
}
  }

AuthStack. js

import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import SignupScreen from '../screens/SignupScreen';
import LoginScreen from '../screens/LoginScreen';
const Stack = createStackNavigator();
export default function AuthStack() {
  return (
    <Stack.Navigator initialRouteName='Login'>
      <Stack.Screen
        name='Login'
        component={LoginScreen}
        options={{ header: () => null }}
      />
      <Stack.Screen name='Signup' component={SignupScreen} />
    </Stack.Navigator>
  );
}

Экран входа

import React, { useState, useContext } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Image } from 'react-native';
import FormButton from '../components/FormButton';
import FormInput from '../components/FormInput';

import { AuthContext } from '../navigation/AuthProvider';

export default function LoginScreen({ navigation }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const { login } = useContext(AuthContext);
  return (

    <View style={styles.container}>
      <FormInput
        value={email}
        placeholderText='Email'
        onChangeText={userEmail => setEmail(userEmail)}
        autoCapitalize='none'
        keyboardType='email-address'
        autoCorrect={false}
      />
      <FormInput
        value={password}
        placeholderText='Password'
        onChangeText={userPassword => setPassword(userPassword)}
        secureTextEntry={true}
      />
      <FormButton buttonTitle='Login' onPress={() => login(email, password)} />
      <TouchableOpacity
        style={styles.navButton}
        onPress={() => navigation.navigate('Signup')}
      >
        <Text style={styles.navButtonText}>New user? Join here</Text>
      </TouchableOpacity>
    </View>

  );
}

AuthProvider. js

import React, { createContext, useState } from 'react';
import auth from '@react-native-firebase/auth';

export const AuthContext = createContext({});

export const AuthProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    return (
      <AuthContext.Provider
        value={{
          user,
          setUser,
          login: async (email, password) => {
            try {
              await auth().signInWithEmailAndPassword(email, password);
            } catch (e) {
              console.log(e);
            }
          },
          register: async (email, password) => {
            try {
              await auth().createUserWithEmailAndPassword(email, password);
            } catch (e) {
              console.log(e);
            }
          },
          logout: async () => {
            try {
              await auth().signOut();
            } catch (e) {
              console.error(e);
            }
          }
        }}
      >
        {children}
      </AuthContext.Provider>
    );
  };

export const currentUser = auth().currentUser;

HomeScreen. js

import React, { Component, useContext, useState} from 'react';
import { Alert, Button, View, Text, Image, PermissionsAndroid, TouchableHighlight, TextInput } from 'react-native';
import { styles, buttons } from './styles' 
import auth from '@react-native-firebase/auth';
import FormButton from '../components/FormButton';
import { AuthContext } from '../navigation/AuthProvider';

export default function HomeScreen(props) {

  const { route, navigation } = props

  const { user, logout } = useContext(AuthContext);

  function  navigate() {
    console.log("User Logged In", auth().currentUser.uid);
    console.log("Navigating to Screen 1 ....");
    navigation.navigate('Screen1');
  }

  return (
        <View>
          <View style={styles.container}>
          <Text style={styles.description}>You are logged in as {user.email}</Text>
          <FormButton buttonTitle="Get Started" onPress={()=> navigate()} />
          <FormButton buttonTitle='Logout' onPress={() => logout()} />
         </View>
         </View>
      );
}

Screen1. js

import React, { Component } from 'react';
import { Alert, Button, View, Text, Image, PermissionsAndroid, TouchableHighlight } from 'react-native';
import { styles } from './styles' 
import { db } from '../config';
import { WriteSessionData} from '../utils/helpers';
import storage from '@react-native-firebase/storage';
import { currentUser } from '../navigation/AuthProvider';
import FormButton from '../components/FormButton';

class Screen1 extends Component {

  _isMounted = false;
  
    constructor(props) {
        super(props);
       
        this.state = {
          sessionID: '12345' //random id that will be passed down
        };        
      }

      componentWillUnmount() {
        clearInterval(this._progressInterval);
        this._isMounted = false;
      }
  
      componentDidMount() { 

        this._isMounted = true;


        console.log("User ID in Screen 1 componentDidMount", currentUser.uid);
        WriteSessionData(this.state.sessionID);

        if(this._isMounted){
          //do some other commands
        }        
      }

render() {
      return (
        <View>
          <Text style={styles.title}>Screen 1</Text>
          <Text style={styles.description}>User Email: {currentUser.email} 
          </Text>
         </View> 
      );
    }
  }
  
  export default Screen1;

Я даже могу вернуть пользователя UID в console.log. Я также вижу, что пользователь вошел в систему через веб-консоль Firebase.

Мне не хватает добавления некоторых привилегий в IAM? Есть ли проблема с заголовком ответа с библиотеками React Native или что-то, что я должен решить.

У меня установлены следующие библиотеки и версии:

    "@react-native-firebase/app": "^8.2.0",
    "@react-native-firebase/auth": "^8.2.0",
    "@react-native-firebase/firestore": "^7.4.3",
    "@react-native-firebase/storage": "^7.2.2",
    "@react-navigation/native": "^5.6.1",
    "@react-navigation/stack": "^5.6.2",
    "firebase": "^7.16.0",
    "react": "16.11.0",
    "react-native": "0.62.2",

1 Ответ

1 голос
/ 05 августа 2020

Интересно, ваш файл Config.js сбивает с толку SDK. Согласно response-native-firebase docs :

В отличие от Firebase Web SDK, нет необходимости вручную вызывать метод initializeApp с учетными данными вашего проекта. Собственные SDK Android и iOS автоматически подключаются к вашему проекту Firebase с использованием учетных данных, предоставленных на этапах установки Начало работы .

Кроме того, вы можете рассмотреть либо :

  • Избавиться от AuthProvider.js и просто вызвать библиотеку @react-native-firebase/auth напрямую, когда вам нужно проверить состояние авторизации или информацию о пользователе

или:

  • Переместите слушателя onAuthStateChanged в AuthProvider.js и убедитесь, что вы используете AuthProvider вместо прямого вызова @react-native-firebase/auth.

Выбор одного из этих вариантов вместо небольшого и то и другое поможет вам отслеживать, что происходит с вашим состоянием авторизации.

...