Firestore特权不足或不足以及对本机做出反应

时间:2020-08-04 19:01:38

标签: reactjs firebase react-native google-cloud-firestore firebase-security

我是Firebase和React Native的新手。向应用程序添加电子邮件身份验证并更新身份验证规则时,出现缺少或权限不足错误。

尝试在Screen1的componentDidMount函数中写入Firestore时收到错误。

我为我的应用添加了以下规则。

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>
  );
}

Routes.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>
  );
}

Helper文件(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;

我什至可以在console.log中返回用户的UID。我还可以看到用户通过Firebase Web控制台登录。

我是否想在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 个答案:

答案 0 :(得分:1)

我想知道您的Config.js文件是否混淆了SDK。根据{{​​3}}:

与Firebase Web SDK不同,无需使用项目凭据手动调用initializeApp方法。原生Android和iOS SDK使用react-native-firebase docs安装步骤中提供的凭据自动连接到Firebase项目。

此外,您可能要考虑以下任一情况:

  • 在需要检查身份验证状态或用户信息时,摆脱AuthProvider.js并直接调用@react-native-firebase/auth

或:

  • 将您的onAuthStateChanged侦听器移至AuthProvider.js,并确保您使用AuthProvider而不是直接调用@react-native-firebase/auth

选择其中一个而不是两个都可以帮助您跟踪身份验证状态。