Take user back to previous page after logging in (Node) - angularjs

I want to be able to redirect unauthenticated users from an individual post's page to the login and then back to the post after the user has logged in.
My login route is like this:
router.get('/login', function(req, res, next){
if (req.user){
res.redirect('/wall');
} else {
res.render('login');
}
});
My wall router looks like this:
router.get('/wall', function(req, res, next){
res.render('wall');
});
The post URL will be something like:
http://thisisnotarealdomain.com/wall#/post/ID
My stack is: NodeJS and Angular for the SPA
How do I do that?
Thanks,

First of all, I would create a middleware function to handle the redirection in case the user is not logged in, something like this:
const checkLogin = (req, res, next) => {
// Checks if the user is logged in
if(!userIsLoggedIn) {
// If user is not logged in
// Get relative path of current url
const url = req.originalUrl;
// And redirect to login page, passing
// the url as a query string that Angular
// can access later
res.redirect(`/login/?redirect=${url}`);
} else {
// If user is logged in
// go on and render the page
next();
}
}
router.get('/wall', checkLogin, function(req, res, next){
res.render('wall');
});
This way, if the user is not logged in, you would get redirect to an url like
/login/?redirect=/wall/post/14.
Then in your Angular code, you would wait for the login promise from Node and simply do a redirect to that query string we have: redirect. Something like this:
// Assuming you're logging from a service
angular
.service('LoginService', function($location, $window) {
// Generic login (could be $http, $resource, restangular)
LOGIN_PROMISE
.then(function(res) {
// If login was successful
if(res.success) {
// $location.search() allows you
// to access query strings
var redirectTo = $location.search().redirect;
// And then redirect to the page the
// user were before being redirected
// to the login page
$window.location.href = redirectTo;
}
})
})
Or you could do a redirect directly from your backend code:
// On your Angular code
$http({
method: 'GET',
params: {
redirect: $location.search().redirect
}
});
// On Node
router.get('/api/login', (req, res, next) => {
if(passwordIsCorrect) {
// And do the redirect
res.redirect(req.body.redirect);
}
});
This is just one of a lot of ways you can achieve this (that's the beauty of web development).
Hope this may help you!

Related

Redirecting to static page when HTTP method is not found on Node backend

I have a single page app written in AngularJS and NodeJS. On the client side, there are several paths that the user can navigate to:
http://jabaridash.com/#!/home
http://jabaridash.com/#!/interests/travel
When the user types in a path that does not exist such as http://jabaridash.com/#!/foo, AngularJS handles it by rerouting to the /notFound path, and then that page redirects the user back to the home page. This is the code:
$urlRouterProvider.otherwise('/notFound');
This works when the path begins with #!/anyPath. However, if I were to type jabaridash.com/whatever, Angular does not reroute it. I am not sure if that has to do with the fact that I am using $stateProvider and modules to navigate, or I need to handle that type of path on the backend. I am assuming that I need to handle it on the Node side, because I do have one REST endpoint called photography setup on the NodeJS side, which can be accessed via jabaridash.com/photography (without #!). This endpoint works fine, but any other endpoint that I do not have setup will get a response of:
Cannot GET /something
This is to be expected, as there is no endpoint there. So essentially, how do i get NodeJS to redirect to my index.html. The way that I am serving the static page follows:
/**
* #description Set up the server
*
* #param dir directory to serve the index.html from
*/
function setupServer(dir) {
server.use(express.static(dir), function(req, res, next) {
// Allow cross origin from any host
res.setHeader('Access-Control-Allow-Origin', '*');
next();
});
// Set up the photography REST endpoint
photography_controller(server, dir);
}
My photography endpoint is setup as follows:
server.get('/photography', function(req, res) {
var searchPath = '/client/modules/interests/photography/img/thumbnail/';
// Send the list of files for use on client side
res.send(fileList(dir + searchPath, searchPath));
});
Is there a generic way to tell Node to say..."If the endpoint / HTTP method is not defined for a given path, redirect to a known path?"
This snippet below tells express to redirect to not-found when the path start with /example but has no specified handler in the router. Other routes that don't start with /example will not redirect because they won't be routed into the router in the first place.
const express = require('express');
const app = express();
// create a router for /example
var router = express.Router()
.get('/', function (req, res) {
res.send('example home');
})
.post('/about', function (req, res) {
res.send('About example');
})
/* catch all middleware for routes starting
with /example that redirects to /not-found */
.use(function (req, res, next) {
return res.redirect('/not-found');
});
// attach router
app.use('/example', router);
// create a not-found router handler
app.get('/not-found', function (req, res) {
res.send('Not found page');
});
app.listen(3000, () => console.log('App listening on port 3000'));
Right after your routes definition, do the following:
server.get('/photography', function(req, res) {
//do something
});
// catch 404 and forward to error handler
server.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
//
// error handler
server.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
//render the page you want to navigate to. In this example, I navigate the user to google
res.redirect('http://google.com');
});

redirect to another page rather than index after sign in via passport in MEAN.js

I am using MEAN.js to create a CRUD web application.
in this app I use passport for Authentication
It redirect to the index page after signing in
But how can I redirect to another page like my module page?
Cheers!
You need to use authenticate(http://passportjs.org/docs/authenticate)
Use it as a route handler
app.post('/login', passport.authenticate('facebook', function(error, user, info){
if (error) {
log.error(error);
next(error);
} else {
if (user) {
// do the redirect here
} else {
next(new Error("Invalid Request"));
}
}
}));
Or as a middleware
app.post('/login',
passport.authenticate('facebook'),
function(req, res) {
// do redirect here
});
Or use options
app.post('/login',
passport.authenticate('facebook', { successRedirect: '/user',
failureRedirect: '/login' }));

AngularJS $location.path() not working for returnUrl

I have a SPA using AngularJS. I've just added security/authentication and everything appears to work nicely except redirecting after login if a returnUrl exists in the query string.
I have code in my app which will redirect to my login route if no user is authenticated. For example, if a user attempts to access http://localhost:55841/#/group/15 (which requires authentication), it will redirect to the login route with the following URL:
http://localhost:55841/#/login?returnUrl=%2Fgroup%2F15
Here is my login method which should redirect to the returnUrl route if it exists upon successful login:
var login = function (credentials) {
return $http.post(baseUrl + 'api/login', credentials).then(function (response) {
//do stuff
var returnUrl = $location.search().returnUrl;
if (returnUrl) {
$location.path(returnUrl);
//$location.path('/group/15');
}
$location.path('/');
});
};
When I debug the login method, the value of returnUrl is /group/15 which is what I would expect, yet it navigates to the following URL:
http://localhost:55841/#/?returnUrl=%2Fgroup%2F15
Thanks in advance
Logical code error, check this solution and your branches.
var login = function (credentials) {
return $http.post(baseUrl + 'api/login', credentials).then(function (response) {
$rootScope.currentUser = response.data;
$rootScope.$broadcast('currentUser', response.data);
var returnUrl = $location.search().returnUrl;
if (returnUrl) {
console.log('Redirect to:' + returnUrl);
$location.path(decodeURI(returnUrl)); // <- executed first, but not redirect directly.
//$location.path('/group/15');
} else { //else :)
console.log('Redirect returnUrl not found. Directing to "/".');
$location.path('/'); // <- only redirect if no returnUrl isset/true
}
}, function (response) {
$rootScope.currentUser = null;
$rootScope.$broadcast('currentUser', null);
return $q.reject(response);
});
};
Hint: You need to filter lot of URL in your "returnUrl". Think about a case where the last page was /. So its a endless loop.

How to redirect users to original request after authentication, Angular-Fullstack Yeoman?

I'm using the Angular-Fullstack yeoman generator as the basis for my project:
https://github.com/DaftMonk/generator-angular-fullstack
I cannot figure out how to redirect users to the link they originally requested after logging in.
Example of what I want to happen:
Unauthenticated user requests http://myapp/videos/video1
User is directed to log in
User successfully authenticates
User is automatically redirected to http://myapp/videos/video1
I am using both the boilerplate local login and boilerplate OAuth.
Thanks for any help!
I figured it out, here are the steps I took to solve this problem. For some reason, Stack Overflow isn't formatting my last 2 code blocks below. I made a gist with the code below (note 3 separate files need to be modified)
https://gist.github.com/dcoffey3296/d27c141ef79bec3ff6a6
store the url to return to in a cookie within the .run() method of client/app/app.js
.run(function ($rootScope, $location, Auth, $cookieStore) {
// Redirect to login if route requires auth and you're not logged in
$rootScope.$on('$stateChangeStart', function (event, next) {
Auth.isLoggedInAsync(function(loggedIn) {
if (next.authenticate && !loggedIn) {
// store the requested url if not logged in
if ($location.url() != '/login')
{
$cookieStore.put('returnUrl', $location.url());
}
$location.path('/login');
}
});
});
});
for Oauth, check for this cookie and redirect if it exists in server/auth/auth.service.js
function setTokenCookie(req, res) {
if (!req.user) {
return res.json(404, { message: 'Something went wrong, please try again.'});
}
var token = signToken(req.user._id, req.user.role);
res.cookie('token', JSON.stringify(token));
// return the user to the request page (oAuth) or homepage
if (typeof req.cookies.returnUrl != 'undefined')
{
res.redirect(req.cookies.returnUrl.replace(/"/g, "") || '/');
}
else
{
res.redirect('/');
}
}
for local login, check for cookie in the .then() part of $scope.login(), file: client/app/account/login/login.controller.js
.then( function() {
// Logged in, redirect to home
if (typeof $cookieStore.get('returnUrl') != 'undefined' && $cookieStore.get('returnUrl') != '')
{
$location.path($cookieStore.get('returnUrl'));
$cookieStore.remove('returnUrl');
}
else
{
$location.path('/');
}
})
What I did in a similar case, is that when I redirected user to login page, I attached to the url (as a query parameter) the initial path that user was trying to access eg. path_to_login?requested_url=/videos/video1. So when the login was completed successfully I just read requested_url query parameter and if that existed, user was redirected to the specified path.

Authentication when using angularjs and passportjs

I am currently using passportjs for authenticaton.
I have come across a stage where i need to ensure the user is authenticated if the url is typed in the browser/ I have been using the passportja example which has the following:
app.get('/admin', ensureAuthenticated, function(req, res){
console.log('get admin');
res.render('admin', { user: req.user });
});
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}
I am using angularjs for routing so my get does not work and run the ensure authenticated.
How should this be implemented?
With AngularJS, you need to restrict the display of templates to the user.
So, let us say you have the following code in AngularJS:
$routeProvider.when('/admin', {
templateUrl: '/partials/admin-page.html'
});
When the user tries the /admin route, AngularJS will then request the template /partials/admin-page.html.
Thus, in your nodeJs server, you then implement the following code:
app.get('/partials/admin-page.html', ensureAuthenticated, function (req, res) {
res.render('admin', { user: req.user});
});

Resources