17

As the title said. I need to link authenticated user to database. So that different user can only see their data.

I had successfully implement the Authentication function of Firebase. But the record does not save to Realtime Database and I don't know how to do this.

Can anyone please teach me how do I do such function? I tried the database and I roughly know it use (push) to create a unique ID to differentiate user. But still I have no idea how to combine this to authentication function.

The following code is my function of Login() and Register()

login (){

    const validate = this.refs.formId.getValue();
    if (validate) {
        firebase.auth().signInWithEmailAndPassword(validate.email, validate.password)
        .then(() => {
        })
        .catch((error) => {
            const errorCode = error.code;
            const errorMessage = error.message;
            if (errorCode === 'auth/wrong-password') {

            Toast.show({ text: `${Strings.ST30}`, position: 'bottom', buttonText: `${Strings.ST33}` })

            }
            else if (errorCode === 'auth/user-not-found') {

            Toast.show({ text: `${Strings.ST31}`, position: 'bottom', buttonText: `${Strings.ST33}` })

            }
            else{
            Toast.show({ text: `${Strings.ST32}`, position: 'bottom', buttonText: `${Strings.ST33}` })
            }

        });
    }

}
    register () {

    const validate = this.refs.form.getValue();
    if(this.validate) {
        const errorHandler = ((e)=>{
        console.log(e);
        if(e.code == 'auth/email-already-in-use'){
            Toast.show({ text: `${Strings.ST36}`, position: 'bottom', buttonText: `${Strings.ST33}` })

        } else {
            Toast.show({ text: `${Strings.ST32}`, position: 'bottom', buttonText: `${Strings.ST33}` })
        }

    })
    firebase.auth().createUserWithEmailAndPassword(validate.email,validate.password).then((response) => {
        firebase.auth().currentUser.updateProfile({
            displayName : validate.name,
        }).then(()=>{
        }).catch(errorHandler);

    }).catch(errorHandler)
}}

Thank you so much for your time and help. Appreciate it a lot!

enter image description here enter image description here enter image description here enter image description here enter image description here

Edit 2:

        firebase.auth()
    .createUserWithEmailAndPassword(validate.email,validate.password)
    .then((response) => {
        firebase.auth().currentUser.updateProfile({
            displayName : validate.name,
        }).then(()=>{
            firebase.database()
            .ref('users/' + firebase.auth().currentUser.uid + "/profile")
            .set({
                Username: validate.name,
                UserEmail: validate.email,
                CreationDate: d1.getFullYear() + "/" + (d1.getMonth() + 1) + "/" + d1.getDate()
            })
        }).catch(errorHandler);
    }).catch(errorHandler)
}}

I had successfully link to Firebase Realtime Database. enter image description here

But I can't write and read other function from my database. This is my rules for Firebase Database. May I know which part should I change?

{
"rules": {
    ".read": false,
    ".write": false,
    "users":
    {
        "$userId":
        {
            ".read": "auth.uid === $userId",
            ".write": "auth.uid === $userId"
        }
    }
}

}

Edit 3: (ExampleSendData.js)

constructor(props) { super(props)
this.state = { message: '', messages: [] }

this.addItem = this.addItem.bind(this); }

    componentDidMount() {
        firebase
        .database()
        .ref()
        .child("messages")
        .once("value", snapshot => {
            const data = snapshot.val()
            if (snapshot.val()) {
            const initMessages = [];
            Object
                .keys(data)
                .forEach(message => initMessages.push(data[message]));
            this.setState({
                messages: initMessages
            })
            }
        });

        firebase
        .database()
        .ref()
        .child("messages")
        .on("child_added", snapshot => {
            const data = snapshot.val();
            if (data) {
            this.setState(prevState => ({
                messages: [data, ...prevState.messages]
            }))
            }
        })

    }

    addItem () {
        if (!this.state.message) return;

        const newMessage = firebase.database().ref()
                            .child("messages")
                            .push();
        newMessage.set(this.state.message, () => this.setState({message: ''}))
    }

    render() {
        return (
        <View style={styles.container}>
            <View style={styles.msgBox}>
            <TextInput placeholder='Enter your message'
                value={this.state.message}
                onChangeText={(text) => this.setState({message: text})}
                style={styles.txtInput}/>
            <Button title='Send' onPress={this.addItem}/>
            </View>
            <FlatList data={this.state.messages}
            renderItem={
                ({item}) => 
                <View style={styles.listItemContainer}>
                <Text style={styles.listItem}> {item}
                </Text>
                </View>
            }

            />
        </View>
        );
    }
    }
Alex Chong
  • 341
  • 2
  • 5
  • 9
  • Possible duplicate of [How do I link each user to their data in Firebase?](https://stackoverflow.com/questions/30910704/how-do-i-link-each-user-to-their-data-in-firebase) – André Kool Jan 24 '19 at 15:36

2 Answers2

9

From the code you are writing I expect you are using react-native-firebase? If not - you should use it :-)

Solution for react-native-firebase:

As soon as you are registered or logged in you can use the firebase.auth().currentUser Object. This object includes a uid (currentUser.uid). You can then push some data to the database under the uid with something like firebase.database().ref('users/' + firebase.auth().currentUser.uid + "/profile").set(); For example in your register like this:

    register () {
        const validate = this.refs.form.getValue();
        if(this.validate) {
            const errorHandler = ((e)=>{
            console.log(e);
            if(e.code == 'auth/email-already-in-use'){
                Toast.show({ text: `${Strings.ST36}`, position: 'bottom', buttonText: `${Strings.ST33}` })
            } else {
                Toast.show({ text: `${Strings.ST32}`, position: 'bottom', buttonText: `${Strings.ST33}` })
            }
        })
        firebase.auth().createUserWithEmailAndPassword(validate.email,validate.password).then((response) => {
            firebase.auth().currentUser.updateProfile({
                displayName : validate.name,
            }).then(()=>{
                firebase.database().ref('users/' + firebase.auth().currentUser.uid + "/profile").set(firebase.auth().currentUser);
            }).catch(errorHandler);
        }).catch(errorHandler)
    }}

Security:

I do not recommend to set the whole user data in your database, since you do not need it there. Use the database to save user progress or something similar.

Security 2:

You should set the security rules of your database, that only the user can read and write in his db node. Use something like:

{
    "rules": {
        ".read": false,
        ".write": false,
        "users":
        {
            "$userId":
            {
                ".read": "auth.uid === $userId",
                ".write": "auth.uid === $userId"
            }
        }
    }
}

Edit 1: Please try to remove push since it generates a unique key, which has nothing to do with the user. It will be hard to find your user data again. And do not use set twice since it won't work. enter image description here

Edit 2: You have to set the nodes you want to be readable/writable to true like this:

{
    "rules": {
        ".read": false,
        ".write": false,
        "users":
        {
            "$userId":
            {
                ".read": "auth.uid === $userId",
                ".write": "auth.uid === $userId"
            }
        },
        // readable node
        "messages":
        {
            ".read": true
        },
        // readable and writable node
        "messages":
        {
            ".read": true,
            ".write": true
        }
    }
}
Alexander Kuttig
  • 426
  • 3
  • 10
  • Hi, thank you for the help. I change the code to yours for Register() , I register a new account, the database still not recorded the latest user created. And yes, I do change the rules to your suggestion too. – Alex Chong Jan 24 '19 at 14:55
  • Can you log your user after updating the profile like firebase.auth().createUserWithEmailAndPassword(validate.email,validate.password).then((response) => { firebase.auth().currentUser.updateProfile({ displayName : validate.name, }).then(()=>{ console.log(firebase.auth().currentUser); }).catch(errorHandler); }).catch(errorHandler) – Alexander Kuttig Jan 25 '19 at 08:53
  • It could also be possible that firebase.auth().currentUser could not be written to db completely. Have you tried to write your own object like firebase.database().ref('users/' + firebase.auth().currentUser.uid + "/profile").set({name: validate.name}); – Alexander Kuttig Jan 25 '19 at 08:56
  • Sorry for the late reply @Alexander , I edited my post with screenshot of my code. Hope you can help me out. I still stuck at the database link. – Alex Chong Jan 28 '19 at 16:28
  • Hi Alex, please copy your code next time since it will be much more comfortable to edit :-) I also edited my answer with a screenshot - please try if that works. If not, could you please check if the firebase database call is even reached and if your auth().currentUser.uid is set? Just put a console.log(firebase.auth().currentUser) right before the call and check if the uid is in there.... – Alexander Kuttig Jan 29 '19 at 07:58
  • Thank you again @Alexdander, I had successfully link new register user to database. But I can't read and write to database with the rules set you previously shown. Can you help me with it? Which part should I change? – Alex Chong Jan 29 '19 at 11:12
  • If I change the 'false' to 'true', it can be read and write. But it is not private, I wanted to make it private to each user. – Alex Chong Jan 29 '19 at 11:13
  • I had editted the post. I posted my code of my function of reading database (ExampleSendData.js), I am not sure is my code problem of not reading it or it is problem on the Rules set. – Alex Chong Jan 29 '19 at 11:17
  • You have to set your firebase rule for every node you want to access. You can make single nodes readable or writable. Or you can have a subnode with user id, which can be readable or writable only for the user with the corresponding id (like it is for your users node). Since the original question is answered, please accept the answer. – Alexander Kuttig Jan 29 '19 at 16:20
  • Thank you again @Alexander Kuttig. I fix the security by doing this firebase .database() .ref('users/'+ firebase.auth().currentUser.uid + 'Task/') .on("child_added", data => { Now the user can only read it own data. Most of my problem on my App already fixed. Thank you again for your kindly help! Appreciate it alot – Alex Chong Jan 30 '19 at 09:26
1

You will need to get current user once logged in using firebase.auth.getcurrentuser(), then write the information to the data base firebase.database().ref('users/' + firebase.auth().currentUser.uid or currentuser.email if you want to write the email to database also check security rules are set.

Christopher Moore
  • 15,626
  • 10
  • 42
  • 52
Foton
  • 97
  • 1
  • 9
  • If not mistaken, Firebase Realtime Database doesn't allow to add emails as key. Correct me if I'm wrong. – AbhinayMe Sep 07 '20 at 02:57