Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using vuefire with Auth (getting currentUser) #59

Closed
nachocab opened this issue Jan 22, 2017 · 8 comments
Closed

Using vuefire with Auth (getting currentUser) #59

nachocab opened this issue Jan 22, 2017 · 8 comments
Labels

Comments

@nachocab
Copy link

nachocab commented Jan 22, 2017

I've been looking at #18, #47 and #48, but I'm still confused about the best way to deal with authentication using vuefire.

On my main.js I'm using woodberry's approach and calling the unsubscribe function after authentication:

const unsubscribe = fb.auth().onAuthStateChanged((user) => {
  new Vue({
    el: '#app',
    template: '<App/>',
    components: { 
      App 
    },
    router
  });

  // stop listening
  unsubscribe()
})

My understanding is that by using this pattern, we delay the creating of the Vue instance until Firebase authenticates the user.

On my routes.js I use beforeEnter navigation guards to ensure that the user is authenticated:

    function requireAuth(to, from, next) {
      if (!fb.auth().currentUser) {
        console.log("User is not logged in");
        next({
          path: '/auth',
          query: { redirect: to.fullPath }
        })
      } else {
        console.log("User is logged in:", auth.currentUser.uid);
        next()
      }
    }

    export default [
      { 
        path: '/students', 
        component: StudentIndex,
        beforeEnter: requireAuth
      }
    ]

Then on my StudentIndex.vue component, I access the firebase database reference /users/${uid}/students, but when I load the http://mydomain.com/students URL, I get an error:

  export default {
    // this doesn't work: Uncaught TypeError: Cannot read property 'uid' of null
    firebase: {
      students: firebase.database().ref('users')
                  .child(firebase.auth().currentUser.uid)
                  .child('students')
    }
  }

However, if I create the reference manually using $bindAsArray in the created hook, it works:

  export default {
    // this works
    created() {
      this.$bindAsArray('students', 
        firebase.database().ref('users')
          .child(firebase.auth().currentUser.uid)
          .child('students')
        )
    }
  }

Is this to be expected or am I missing something?

The thought of having to define my firebase references differently depending on whether the path includes the user id or not seems a little weird, so I'm sure I must be missing something.

@nachocab
Copy link
Author

nachocab commented Jan 22, 2017

I guess an alternative could be this:

    firebase(){
      const userId = firebase.auth().currentUser.uid
      return {
        students: db.ref('users')
                    .child(userId)
                    .child('students')
      }
    }

@posva
Copy link
Member

posva commented Jan 22, 2017

About the Uncaught error, that's normal, the code gets executed before the component is actually used. Using the function syntax, as you pointed out is the way to go.

About the user authentication, I'd personally not wait until the user is authenticated but rather use a different view to auth. That'd create a better UX and faster load time, but your approach is perfectly fine too.

@posva posva closed this as completed Jan 22, 2017
@posva posva added the question label Jan 22, 2017
@nachocab
Copy link
Author

@posva Thanks, do you have an example of using a dedicated view to authenticate? The reason why I used this approach is because I don't want users to log in every time they refresh the page

@posva
Copy link
Member

posva commented Jan 22, 2017

Sorry, I don't 😕
Basically the view at / would trigger that in some hook and then redirect to an authed view
Or a redirect would always go to a /login view if not authenticated

@alekbarszczewski
Copy link

alekbarszczewski commented Feb 25, 2017

I am using following approach with vue-router & vuex:

App.vue (wrapper component of whole application):

<template>
  <!-- router-view wont be rendered unless user is either authenticated or not -->
  <!-- you can display loader here for example -->
  <router-view v-if="user !== null" />
</template>

<script>
  import Firebase from 'firebase';
  import { mapState } from 'vuex';

  export default {
    computed: {
      ...mapState(['user']),
    },
    beforeCreate () {
      Firebase.auth().onAuthStateChanged((user) => {
        // initially user = null, after auth it will be either <fb_user> or false
        this.$store.commit('setUser', user || false);
        if (user && this.$route.path === '/login') {
          this.$router.replace('/');
        } else if (!user && this.$route.path !== '/login') {
          this.$router.replace('/login');
        }
      });
    },
  };
</script>

store.js:

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    user: null,
  },
  mutations: {
    setUser (state, value) {
      state.user = value;
    },
  },
});

SomeComponent.vue

<template><div>{{ user.email }}</div></template>
<script>
import { mapState } from 'vuex';
export default {
  computed: {
      ...mapState(['user']),
    },
}
</script>

@mdmullins
Copy link

@alekbarszczewski why are you using mutations instead of actions in this example? specifically: this.$store.commit('setUser', user || false);
Isn't it best practice to this.$store.dispatch('setUser', user || false)? Though I can't get this to work. Is it something to do with async?

@posva
Copy link
Member

posva commented Mar 7, 2017

@mdmullins It's probably specific to your app so you should ask on the forum.
setUser is probably just doing state.user = user so it's better to have a mutation there

@alekbarszczewski
Copy link

@mdmullins Action is not required here because setUser does not do any asynchronous stuff - it simply sets user object in state. But you could wrap it in action if you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants