Meteor.user() login issue - meteor

I am testing a restrict login function with router code below
var requireLogin = function() {
if (! Meteor.user()) {
console.log("user not logged");
this.next()
} else {
console.log("user logged");
this.next()
}
}
Router.onBeforeAction(requireLogin, {except: ['home','login','about']});
when I try to enter restricted area like userprofile it ask me to log in and print "user not logged"
and after I successfully log in and try to access that area again. it printing both code starts with "user not logged" and then "user logged"
I want to know how to avoid this to happen? since some page become glitched when this happened.
I want it to only print "user logged" if I enter a restricted area page.
Any help would be appreciated.

You need to integrate Meteor.loggingIn() somewhere in your requireLogin function. Because, what's happening is that Meteor is still loading the user system and for every route change, it re-authenticates the user based on current session, if it exists.
var requireLogin = function() {
if(!Meteor.user()){
if(Meteor.loggingIn()){
this.render(this.loadingTemplate);
}else{
this.render('accessDenied');
}
}else {
this.next();
}
}
You will notice that it uses this.loadingTemplate. To keep this, you must also configure your routes to have a loading template. e.g.:
Router.configure({
loadingTemplate: 'loading'
});
or you could just simply swap that out with this.render('loading'); where 'loading' is the template name of your 'Now loading' yield/page.

Related

can not get current user after page refresh in Meteor.js

i'm trying to display Logged in User name .
After login i can get user name but once i refresh page it is undefined .
My code :
<p>{{currentUser.profile.full_name}}</p>
i try other way too
blaze Side
{{currentUser}}
js
Template.main.helpers({
"currentUser": function() {
if (Meteor.user())
return Meteor.user().profile.full_name;
}
});
after login i can get name but i can not get name after refresh page.
So, what is solution for get name if i refresh page in Meteor blaze ?
Try this:
Template.Default.onCreated(function() {
this.user = Meteor.user();
});
Template.main.helpers({
currentUser: function() {
var user = Template.instance().user;
if (user) {
return user.profile.full_name;
}
});
Also make sure that profile.full_name exists;

user object not loaded after logging out and quickly logging back in in Meteor

I am facing a strange behaviour, and can't debug it properly. I need your help.
If I log out of Meteor, everything seems fine.
If I wait for around 2 seconds and log back in again, everything is still very fine. But if I logout and quickly login again, right after the login process, the Meteor.user() object is set to null, which leads my router to redirect the user back to the login page.
Any idea why this is happening, and how could I prevent it?
I have spent 2h trying several things without success. Any suggestion is most welcome.
EDIT
This is my global onBeforeAction function :
Router.onBeforeAction(function() {
// Ensures the user is logged in
if (!Meteor.userId()) {
please_login();
}
// Email address not verified for 24h? Please verify it!
else {
var self = this;
// Waits for the user object to be passed over DDP
function wait_for_user_data() {
if (Meteor.user() && Meteor.user().emails && Meteor.user().profile) {
var user = Meteor.user();
var now = new Date().getTime();
var ca = user.createdAt.getTime();// Created At
var cs = (now - ca) / (24 * 60 * 60 * 1000);// Created Since (in days)
var urls = ["email_verification_required", "email_verification"];
if (cs > 1 &&
!user.emails[0].verified &&
urls.indexOf(self.url.split("/")[1]) == -1) {
Router.go("email_verification_required");
}
else {
self.next();
}
}
else {
setTimeout(wait_for_user_data, 500);
}
}
wait_for_user_data();
}
},
{except: ['home', 'login', 'register', 'password_recovery', "email_verification", "profile"]})
What actually happens is the following :
When I login right after having logged out, self.next() is called, but the current user properties (Meteor.user().emails and Meteor.user().profile) aren't loaded yet for some reason. They are undefined. As you can see, I tried to work around this by waiting until they are defined, but then I receive the following error message :
Route dispatch never rendered. Did you forget to call this.next()
in an onBeforeAction?
This seems to cause Meteor to set Meteor.user() to null, and so my user gets redirected to the login page...
EDIT BIS
This is how I am handling the publish/subscribe of the users data. I have 2 different pub/sub set, one for all users, and the other one for the logged in user only.
Meteor.publish('users', function() {
var args = {};
var fields = {
'_id': 1,
'createdAt': 1,
'profile.firstname' : 1,
'profile.lastname' : 1,
'profile.lang' : 1,
};
// Only admins can access those sensible information
if (this.userId && Roles.userIsInRole(this.userId, 'admin')) {
fields["emails"] = 1;
fields["profile.celular"] = 1;
args : {$ne : {_id: this.userId}};
}
return Meteor.users.find(args, {fields: fields});
});
Meteor.publish('user', function() {
return Meteor.users.find({_id: this.userId});
});
This is how I subscribe to those two publications within my router's configurations :
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
waitOn: function() {
return [Meteor.subscribe('user'), Meteor.subscribe('users')];
},
});
Without a code example (and knowing which router you're using) I'm going to take a guess that you're router code looks something like :
if (!Meteor.user()) {
//... redirect or change tempalte etc
}
There is another value you can check,
if (!Meteor.user() && !Meteor.loggingIn()) {
//... redirect or change tempalte etc
}
you can use various combinations of these to handle the login state, such as having a logging in loading view etc
With more information
The redirect is being called in a callback, currently for the login with password function, having a look at the docs it should be called on the onLogin callback linked as this ensures that login was successful, though doing the redirect here, may not provide the same range of control as doing this in a reactive context such as a before hook on a controller, or an autorun function created in the login template onCreated callback.
The way I've deal with this in the past is to define an explicit subscription to the user object then waitOn that subscription in the router. Much simpler than writing a polling loop but mostly I did it because I needed specific fields that didn't come over by default. Hopefully this can help you with your problem.
Server:
Meteor.publish('me',function(){
if ( this.userId ){
// return the fields I need
return Meteor.users.findOne({ _id: this.userId },{ fields: { field1: 1, field2: 1, ... }});
}
else this.ready();
});
Router:
waitOn: function(){
return Meteor.subscribe('me');
}

Iron router onBeforeActions is redirecting to startpage

I use onBeforeActions to check if users are logged in, if their profile is incomplete or disabled. This seems to work correctly.
But now the problem is whenever I directly go to a page within the app, I get redirected to startPage as well. I debugged and discovered 'user' is undefined, although I'm logged in. I use accounts-fb & -tw and account-ui packages.
How can I make sure the user is logged in? I don't understand the correct timing of the functions..
edit:
Locally I don't always seem to have this problem. user is often defined. But on my production server (I just uploaded it with a debugger statement, yes I have no testserver :/) it always seems to be undefined and forwarding me to the startPage..
router.js:
if (Meteor.isClient) {
// only for client, else the serverside router will try to run this onBeforeAction
var onBeforeActions;
onBeforeActions = {
loginRequired: function() {
var user = Meteor.user();
if (!user) {
Router.go('startPage');
} else {
if (user && user.profile && user.profile.incomplete) {
Router.go('completeSignup');
}
if (user && user.profile && user.profile.disable) {
Router.go('profileEdit');
}
}
this.next();
}
};
Router.onBeforeAction(onBeforeActions.loginRequired);
Router.configure({
notFoundTemplate: 'notFound',
layoutTemplate: 'layoutMain',
loadingTemplate: 'loading',
trackPageView: true
});
Router.map ({});
}
Is the user in the middle of logging in? What does Meteor.loggingIn() return? Here is my login check using Iron Router in Coffeescript.
requireLogin = ->
if not Meteor.user()
if Meteor.loggingIn()
this.render this.loadingTemplate
else
this.render 'accessDenied'
else
this.next()
Try something simple like this, and then add the little bits of what you want to do after. But I'm fairly sure Meteor.loggingIn() is what you're looking for here.
Here is the documentation on it: http://docs.meteor.com/#/full/meteor_loggingin
EDIT: It probably works locally because there isn't any latency so if you're logged in it can run everything immediately. If that makes sense.

Correct way to manage routes after sign in for different roles

I have 2 roles, admins and users. I have a home route '/' that is just a sign in page. When admin users sign in they must go to one route ('adminPortal') and when user users log in they must go to the 'userPortal' route. On signing out both roles should route back to '/'.
Before I had an admin role, I was routing on sign in like so:
Router.onBeforeAction(function() {
this.render('loading');
if (! Meteor.userId()) {
this.render('Home');
} else {
this.next();
}
});
which worked fine (actually it was breaking my waitOn: render loading template stuff which I just discovered but more on that later). I then added roles like this (from a Stack Overflow answer I can't find right now):
server/
insertUsers=function(){
var adminId=Accounts.createUser({
username:"admin",
password:"password"
});
Roles.addUsersToRoles(adminId,"admin");
var userIdd = Accounts.createUser({
username:"user",
password:"password"
});
Roles.addUsersToRoles(userIdd,"user");
};
and
Meteor.startup(function () {
// always start from scratch (you will want to comment this line at some point !)
Meteor.users.remove({});
if(Meteor.users.find().count()===0){
insertUsers();
}
})
and
Meteor.publish("user", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'roles': 1}});
} else {
this.ready();
}
});
And I tried to route to the user/admin portals like this:
router.js
Router.route('/', {
before: function() {
if (! Meteor.userId()) { // I acutally added this check that the user is not logged in after the infinite loading problem but I thought the question was getting too long so I just left it in rather
this.render('Home')
} else {
if (Roles.userIsInRole(Meteor.user(), 'admin')) {
Router.go('/admin')
} else {
Router.go('/user')
}
}
},
waitOn: function () {
return Meteor.subscribe('user');
}
});
Now this very almost works! If I log is as either user I go to the right portal. However, when I sign out, my onBeforeAction (i.e. first code block in this question) only renders the Home template and does not actually change the URL to '/' (i.e. the URL remains either '/user' or '/admin'). Now when I try log in a second time, it will always take me to the route that I was taken to on the first log in unless I manually change the browser URL to '/'. So I thought I'd just replace the this.render('Home') with a Router.go('/'); but that seems to have created some sort of infinite loop where the Home template never renders (it did incidentally now for the first time correctly render my loading template though).
So thanks for reading all that! What's the right way to do this?
Try adding Router.go('/'); in your logout button event, along with Meteor.logout();
Example:
Template.loginButtons.events({
'click #login-buttons-logout' : function (event, template) {
Meteor.logout(function(err) {
Router.go('/');
});
}
});
I had the same issue as you, and that was the simplest way I've found to return to home page after logout.

Better handle logged_in and logged_out without showing wrong layout in iron-router

i'm trying to get a clean redirection to the login form if the user isn't logged in. This basically works but i often see my main layout which only logged in users should see. I only see it for a second then before the login screen is showing but i'm trying to get rid of this shortly "flickering" faulty page.
My router.js looks a bit like this:
Router.configure({
layoutTemplate: 'layoutPrimary',
loadingTemplate: 'loading',
waitOn: function() {
if (Meteor.user()) {
return Meteor.subscribe('messages');
}
else {
return;
}
}
});
Router.route('/', {name: 'dashboard'});
Router.route('/login', {name: 'login'});
some more routes without anything special (some subscriptions). Now we check if the user is logged in. If not he shall be delivered a special layout containing only the login/register functions.
// require login on all routes
Router.onBeforeAction(function () {
if(!Meteor.user() && !Meteor.loggingIn()){
this.layout('layoutSlim');
this.render('login');
} else {
this.next();
}
});
then we're handling 404s and doing some functions for user check that are used in the routes above.
// 404 Handling
Router.route('/(.*)',function(){
this.render('error404');
});
// Be sure the Meteor.user() exists when settings are loaded
var userIsLoaded = {
ready: function() { return !!Meteor.user(); }
};
var userLoggedIn = function() {
if (!Meteor.user() && !Meteor.loggingIn()) {
this.stop();
Router.go('login');
return false;
}
else {
return true;
}
};
Any idea what i can do to avoid that shortly showing wrong layout? I also sometimes see the login screen when logged in - this is quite rare but it would be a better user experience if this wouldn't happen at all.
I'm not 100% sure if this is related to iron-router or probably an issue that could be handled by spacebars/blaze?
Thanks for helping,
Frank
This is happening because the subscribe('messages') gets done, but the Meteor users collection not.
You can use the currentUser helper from Accounts Package
{{if currentUser}}
<!-- show information here -->
{{else}}
<!-- Forbiden template or login template -->
{{/if}}

Resources