Reputation: 61
I followed the Chirp MEAN stack tutorial to add passportJS authentication to my site (https://github.com/hwz/chirp).
Login and registration is working fine (passport, store and lookup user in MongoDB) as long as I stay in the single page application. If I click refresh / reload in the browser the user seems not to be logged in anymore.
Does someone know how to pick up the session/user of the page after reload? I struggling with it now for several days and can't find anything on the web. Every help is really appreciated.
If the user is not logged in, the site's menu asks for Login/Registration.
If the user is logged in, the menu shows a user dropdown menu.
In Angular I use the following code for the page menu:
<a ui-sref="signin" class="btn btn-success" role="button" ng-hide="authenticated">Login</a>
<a ui-sref="register" class="btn btn-primary" role="button" ng-hide="authenticated">Register</a>
<span class="dropdown" ng-show="authenticated">
<button class="btn btn-success dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{{current_user}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="usermenu">
<li><a ui-sref="#" ng-click="signout()">Logout</a></li>
</ul>
</span>
After page reload ng-show="authenticated" is again false. There is a connect.sid cookie created and still present after page reload. But seems not to be taken into consideration.
AngularApp.js looks like:
var app = angular.module('myApp', ['ui.router']);
...
app.run(function($rootScope, $http)
{
$rootScope.authenticated = false;
$rootScope.current_user = '';
$rootScope.signout = function()
{
$http.get('auth/logout');
$rootScope.authenticated = false;
$rootScope.current_user = '';
};
});
My guess is, that I have to add code here?
AuthenticationController.js looks like:
var app = angular.module('myApp');
app.controller('authController', function($scope, $http, $rootScope, $location)
{
$scope.user = {username: '', password: ''};
$scope.error_message = '';
$scope.login = function()
{
$http.post('/auth/login', $scope.user).success(function(data)
{
if(data.state == 'success')
{
$rootScope.authenticated = true;
$rootScope.current_user = data.user.username;
$location.path('/');
}
else
{
$scope.error_message = data.message;
}
});
};
$scope.register = function(){
$http.post('/auth/register', $scope.user).success(function(data)
{
if(data.state == 'success')
{
$rootScope.authenticated = true;
$rootScope.current_user = data.user.username;
$location.path('/');
}
else
{
$scope.error_message = data.message;
}
});
};
});
Server.js looks like:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var passport = require('passport');
var api = require('./routes/api');
var app = express();
//initialize mongoose schemas
require('./models/models');
var mongoose = require('mongoose'); //add for Mongo support
mongoose.connect('mongodb://localhost/myApp'); //connect to Mongo
app.set('port', process.env.PORT || 3000);
//Middleware
app.use(logger('dev'));
app.use(session({ secret: 'changedforstackoverflow', rolling: true, resave: true, saveUninitialized: false }));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(__dirname + '/../frontend')); //serve static assets
app.use(passport.initialize());
app.use(passport.session());
//// Initialize Passport
var initPassport = require('./passport-init');
initPassport(passport);
var authenticate = require('./routes/authenticate')(passport);
app.use('/api', api);
app.use('/auth', authenticate);
...
I can post more code if it helps. But the authentication in the backend is working fine as far as I can see. Only Angular is not getting the session from the cookie after reload, right?
Upvotes: 3
Views: 1591
Reputation: 61
Ok. I finally managed it.
passport is taking care about the session and the cookie by itself as far as I understood it. I was also not able read data from the cookie, becasue it was protected by HTMLonly attibute.
So, what to do? I added console log in the backend to see if the reload request has still a valid user on backend side.
I added to server.js (backend/node) directly after:
app.use('/auth', authenticate):
this:
app.use(function (req, res, next) {
console.log(req.isAuthenticated());
console.log(req.user);
next();
});
now I have seen in server console that each request after the reload of the page has still a valid user, but angular does not know about it.
I was right about the place to put in some code in my previous posting. App.run has to get the user data from the backend!
So I added this function (frontend/angular):
app.run(function($rootScope, $http, $location)
{
$rootScope.loggedIn = function()
{
$http.post('/auth/isloggedIn').success(function(data)
{
if(data.state == 'success')
{
$rootScope.authenticated = true;
$rootScope.current_user = data.user.username;
$location.path('/');
}
else
{
$rootScope.authenticated = false;
$rootScope.current_user = '';
$location.path('/');
}
});
};
$rootScope.loggedIn();
An for sure now we need to build a function that returns the user data when there is a user loggedin in the backend. The url we're calling in the loggedIn function above, needs to do something. So I added this to the authenticate router (backend/node):
//is logged in
router.post('/isloggedin', function(req, res){
if(req.isAuthenticated())
{
res.send({state: 'success', user: req.user});
}
else
{
res.send({state: 'failure', user: null});
}
});
Last step was to verify that it works with multiple users, so I took two browsers and logged in with different users and refreshed the page. Both users where correctly identified and "auto-logged in".
Hooray! ;-)
Upvotes: 3