From e6a35a7f9acbf7a48e2d946796e128dd060fb953 Mon Sep 17 00:00:00 2001 From: Igor Freire Date: Sun, 22 Mar 2015 11:47:14 -0300 Subject: [PATCH] Enable redirection to previous page after login Two different strategies are adopted, one for when the user authenticates locally and the other through providers. When authenticating locally, the signin function in the client controller redirects to the previous state (storing and using a state name) after successful login. When authenticating through a provider, the first call to provider stores the previous URL (not state, URL) in the session. Then, when provider actually calls the authentication callback, session redirect_to path is used for redirecting user. --- modules/core/client/app/init.js | 8 ++++++ .../authentication.client.controller.js | 24 ++++++++++++----- .../authentication.client.view.html | 26 +++++------------- .../users.authentication.server.controller.js | 27 ++++++++++++++++++- .../users/server/routes/auth.server.routes.js | 12 ++++----- 5 files changed, 65 insertions(+), 32 deletions(-) diff --git a/modules/core/client/app/init.js b/modules/core/client/app/init.js index 94b23b80..c05d9ea3 100644 --- a/modules/core/client/app/init.js +++ b/modules/core/client/app/init.js @@ -32,6 +32,14 @@ angular.module(ApplicationConfiguration.applicationModuleName).run(function($roo } } }); + // Record previous state + $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) { + $state.previous = { + state: fromState, + params: fromParams, + href: $state.href(fromState, fromParams) + }; + }); }); //Then define the init function for starting up the application diff --git a/modules/users/client/controllers/authentication.client.controller.js b/modules/users/client/controllers/authentication.client.controller.js index fed92257..469f190e 100644 --- a/modules/users/client/controllers/authentication.client.controller.js +++ b/modules/users/client/controllers/authentication.client.controller.js @@ -1,7 +1,7 @@ 'use strict'; -angular.module('users').controller('AuthenticationController', ['$scope', '$http', '$location', 'Authentication', - function($scope, $http, $location, Authentication) { +angular.module('users').controller('AuthenticationController', ['$scope', '$state', '$http', '$location', '$window', 'Authentication', + function($scope, $state, $http, $location, $window, Authentication) { $scope.authentication = Authentication; // Get an eventual error defined in the URL query string: @@ -15,8 +15,8 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$http // If successful we assign the response to the global user model $scope.authentication.user = response; - // And redirect to the index page - $location.path('/'); + // And redirect to the previous or home page + $state.go($state.previous.state.name || 'home', $state.previous.params); }).error(function(response) { $scope.error = response.message; }); @@ -27,11 +27,23 @@ angular.module('users').controller('AuthenticationController', ['$scope', '$http // If successful we assign the response to the global user model $scope.authentication.user = response; - // And redirect to the index page - $location.path('/'); + // And redirect to the previous or home page + $state.go($state.previous.state.name || 'home', $state.previous.params); }).error(function(response) { $scope.error = response.message; }); }; + + // OAuth provider request + $scope.callOauthProvider = function(url) { + var redirect_to; + + if ($state.previous) { + redirect_to = $state.previous.href; + } + + // Effectively call OAuth authentication route: + $window.location.href = url + (redirect_to ? '?redirect_to=' + encodeURIComponent(redirect_to) : ''); + }; } ]); diff --git a/modules/users/client/views/authentication/authentication.client.view.html b/modules/users/client/views/authentication/authentication.client.view.html index b5e422ea..779184b6 100644 --- a/modules/users/client/views/authentication/authentication.client.view.html +++ b/modules/users/client/views/authentication/authentication.client.view.html @@ -1,24 +1,12 @@ -
+

Sign in using your social accounts

diff --git a/modules/users/server/controllers/users/users.authentication.server.controller.js b/modules/users/server/controllers/users/users.authentication.server.controller.js index fbb41295..00142eaa 100644 --- a/modules/users/server/controllers/users/users.authentication.server.controller.js +++ b/modules/users/server/controllers/users/users.authentication.server.controller.js @@ -9,6 +9,12 @@ var path = require('path'), passport = require('passport'), User = mongoose.model('User'); +// URLs for which user can't be redirected on signin +var noReturnUrls = [ + '/authentication/signin', + '/authentication/signup' +]; + /** * Signup */ @@ -77,11 +83,30 @@ exports.signout = function (req, res) { res.redirect('/'); }; +/** + * OAuth provider call + */ +exports.oauthCall = function(strategy, scope) { + return function(req, res, next) { + // Set redirection path on session. + // Do not redirect to a signin or signup page + if (noReturnUrls.indexOf(req.query.redirect_to) === -1) { + req.session.redirect_to = req.query.redirect_to; + } + // Authenticate + passport.authenticate(strategy, scope)(req, res, next); + }; +}; + /** * OAuth callback */ exports.oauthCallback = function (strategy) { return function (req, res, next) { + // Pop redirect URL from session + var sessionRedirectURL = req.session.redirect_to; + delete req.session.redirect_to; + passport.authenticate(strategy, function (err, user, redirectURL) { if (err) { return res.redirect('/authentication/signin?err=' + encodeURIComponent(errorHandler.getErrorMessage(err))); @@ -94,7 +119,7 @@ exports.oauthCallback = function (strategy) { return res.redirect('/authentication/signin'); } - return res.redirect(redirectURL || '/'); + return res.redirect(redirectURL || sessionRedirectURL || '/'); }); })(req, res, next); }; diff --git a/modules/users/server/routes/auth.server.routes.js b/modules/users/server/routes/auth.server.routes.js index 02b64718..4c5ed66e 100644 --- a/modules/users/server/routes/auth.server.routes.js +++ b/modules/users/server/routes/auth.server.routes.js @@ -20,17 +20,17 @@ module.exports = function(app) { app.route('/api/auth/signout').get(users.signout); // Setting the facebook oauth routes - app.route('/api/auth/facebook').get(passport.authenticate('facebook', { + app.route('/api/auth/facebook').get(users.oauthCall('facebook', { scope: ['email'] })); app.route('/api/auth/facebook/callback').get(users.oauthCallback('facebook')); // Setting the twitter oauth routes - app.route('/api/auth/twitter').get(passport.authenticate('twitter')); + app.route('/api/auth/twitter').get(users.oauthCall('twitter')); app.route('/api/auth/twitter/callback').get(users.oauthCallback('twitter')); // Setting the google oauth routes - app.route('/api/auth/google').get(passport.authenticate('google', { + app.route('/api/auth/google').get(users.oauthCall('google', { scope: [ 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email' @@ -39,7 +39,7 @@ module.exports = function(app) { app.route('/api/auth/google/callback').get(users.oauthCallback('google')); // Setting the linkedin oauth routes - app.route('/api/auth/linkedin').get(passport.authenticate('linkedin', { + app.route('/api/auth/linkedin').get(users.oauthCall('linkedin', { scope: [ 'r_basicprofile', 'r_emailaddress' @@ -48,10 +48,10 @@ module.exports = function(app) { app.route('/api/auth/linkedin/callback').get(users.oauthCallback('linkedin')); // Setting the github oauth routes - app.route('/api/auth/github').get(passport.authenticate('github')); + app.route('/api/auth/github').get(users.oauthCall('github')); app.route('/api/auth/github/callback').get(users.oauthCallback('github')); // Setting the paypal oauth routes - app.route('/api/auth/paypal').get(passport.authenticate('paypal')); + app.route('/api/auth/paypal').get(users.oauthCall('paypal')); app.route('/api/auth/paypal/callback').get(users.oauthCallback('paypal')); };