Trevor Geise
Trevor Geise

Reputation: 121

Best way to handle user verification in iron router from resume

My basic set up is I have a login page, rep page and manager page.

I've set up my routes in iron router and put in some before hooks to verify that there is a user with proper roles. For the login page I want to see if there is a user, what type of user (using roles), and then send along to their proper page if they are already logged in. For the user type pages I want to check if there is a user, make sure they are in the right place, and if not, send them back to the login page or their correct page.

Each user has a role ('rep',organizationId), and an organization in profile.organization. I check what role they have in their organization.

This all works great except when someone resumes a session. If they start from being logged out, it goes swimmingly, but if they logged in yesterday and open the site back up, it just sits at the login page. I think it's because they are re-logging in.

So, question is, what's the best way to handle checking to see if the user is logged in or logging in. The tricky part is I need to grab data from the user profile to determine where to send them, so if they are logging in, I don't think I can do that. I suspect it has something to do with this.redirect('login') vs this.render('login')

Here is my code for the login route

loginsignupController = BaseController.extend ({
    layoutTemplate: 'loginLayout',
    loadingTemplate: 'loading',
    yieldTemplates: {      
      'header': {to:'header'}
    },
    before: function() {      
      //check if logged in
      if(!!Meteor.user()){
        var org = Meteor.user().profile.organization;
        console.log('logged in');
        //check for rep, manager
        if (Roles.userIsInRole(Meteor.userId(), 'rep', org) ||   Roles.userIsInRole(Meteor.userId(), 'rep', 'default')){
          this.redirect('today')
        } else if (Roles.userIsInRole(Meteor.userId(), ['manager'], org)) {
          //if manager, send to manager home
          this.redirect('managerHome')
        }
      }
    }   
});

and here it is for the rep route (user type a)

RepController = BaseController.extend({
  layoutTemplate: 'repLayout',
  loadingTemplate: 'loading',
  yieldTemplates: {
    'sidebar': {to: 'sidebar'},
    'header': {to:'header'}
  },
  waitOn: function() {
  },
  data: function () {
  },
  before: function(){
      //check if logged in
      if(!Meteor.loggingIn() && !Meteor.user()) {
          this.redirect("/login");
      } else {
        var org = Meteor.user().profile.organization;
        console.log('logged in');
        //check for rep, manager
        if (Roles.userIsInRole(Meteor.userId(), ['manager'], org)) {        
          //if manager, send to manager home          
          this.redirect('/managerHome')          
        }
      };
   }})

Thanks!

Upvotes: 0

Views: 576

Answers (1)

Tarang
Tarang

Reputation: 75975

This behaviour is happening because you've not handled the case where the user's data has not yet arrived from the server.

It works when the user is logged out first, because for them to log in all your subscriptions have to be complete.

So what happens is when you directly load the browser page up, you try to read the user, but the user hasn't yet arrived and it sort of gets stuck. before isn't reactive so when the user does log in nothing will change.

To fix this you need to publish the user's data and subscribe to it with waitOn or this.subscribe(..).wait() in your before.

Another thing to keep in mind is Meteor.user() changes 3 times during the initial load:

  • The first time its null until some data arrives from the server
  • Then some data arrives but the profile fields are empty (unsure of why this is). You directly call Meteor.user().profile.organization when Meteor.user().profile will be null and it would cause an error
  • Finally all the data will be populated and it would be ready to access.

Upvotes: 1

Related Questions