【发布时间】:2020-11-24 22:33:12
【问题描述】:
我是 Firebase 和 React Native 的新手。当我将电子邮件身份验证添加到应用程序并更新身份验证规则时,我收到 Missing or Insufficient Privileges 错误。
我在 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: Missing or enough permissions.]:
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>
);
}
帮助文件(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",
【问题讨论】:
-
如果权限拒绝写入,则写入时 auth 为空。所以你有时间问题。在您尝试访问数据库之前,您的身份验证可能不会被处理。因为您包含了摘录而不是可运行的代码示例,所以这是不可操作的,我只能提供猜测。见how to ask 和creating an mcve。
-
如果我可以在catch的console.log中返回UID,auth可以为null吗? console.log("写入数据库出错", "用户登录为:", currentUser.uid, err);
-
最简单的故障排除方法通常是在您访问数据库之前记录 UID。所以在你的
await session.set({...之前添加一个console.log(firebase.auth().currentUser)并检查它的输出。如果您在此故障排除后无法使其正常工作,请编辑您的问题以包含更新的代码及其输出,以便我们进行检查。 -
我添加了一些额外的代码。我能够在 session.set 之前将日志添加到 UID,并且应用程序能够记录 UID。我仍然收到错误消息。
标签: reactjs firebase react-native google-cloud-firestore firebase-security