Reputation: 1484
I have posted more complex question here AngularJs logout action . But I have another aspect to see, and I think that it should be separated question.
I have Angualr SPA with authentication. Authentication implemented with bearer JWT tokens. I use ng-route
to make different views. Let us imagine, that one view (using /protected
route ,protecetedController
and protectedDataService
) contains protected resources, and another view (using /unprotected
route, unprotecetedController
and unprotectedDataService
) contains unprotected resources. Controllers sample code :
(function () {
'use strict';
angular
.module('protectedCtrl',[])
.controller('protectedController', ['$location','protectedDataService', function ($location, protectedDataService) {
var vm = this;
vm.title = 'protectedController';
protectedDataService.getData().then(function (res) {
vm.values = res.data;
}, function (err) {
console.log(err);
});
}]);
})();
Unprotected controller:
(function () {
'use strict';
angular
.module('unprotectedCtrl',[])
.controller('unprotectedController', ['$location','unprotectedDataService', function ($location, unprotectedDataService) {
var vm = this;
vm.title = 'unprotectedController';
unprotectedDataService.getData().then(function (res) {
vm.values = res.data;
}, function (err) {
console.log(err);
});
}]);
})();
If unlogined user goes to protected resource (/protected
path) he will be redirected to login page. But let us imagine, that logined user press logout button (for now I simply delete from browser local strage my token info and reload page). If user is on /protected
page, he should be redirected to login page. If he is on /unprotected
page nothing should happen. How can I implement this? How can I determine which page is active in ng-view
(needs auth or does not) and make decision about redirection?
Upvotes: 1
Views: 802
Reputation: 5812
You can use the $routeChangeStart
event to catch the change of a route and a helper function to decide whether to redirect to login page or not.
In the run
block of your angular app, define a variable for routes that do not require authentication and a function that checks whether the route the user is heading to is in this list.
angular
.module('awesomeApp')
.run(function (/* inject dependencies */) {
// other code
// Define a list of routes that follow a specific rule. This example
// can be extended to provide access based on user permissions by
// defining other variables that will list routes that require the
// user to have specific permissions to access those routes.
var routesThatDoNotRequireAuthentication = ['/unprotected'];
// Check if current location is contained in the list of given routes.
// Note: the check here can be made using different criteria. For
// this example I check whether the route contains one of the
// available routes, but you can check for starting position, or other criteria.
function rootIsPresent ( route, availableRoutes ) {
var routeFound = false;
for ( var i = 0, l = availableRoutes.length; i < l; i++ ) {
routeFound = routeFound || route.indexOf(availableRoutes[i]) > -1;
}
return routeFound;
}
// And now, when the $routeChangeStart event is fired, check whether
// its safe to let the user change the route.
$rootScope.$on('$routeChangeStart', function () {
// Get the authentication status of a user
var isAuthenticated = authenticationService.isAuthenticated();
var newRoute = $location.url();
// If the route requires authentication and the user is not
// authenticated, then redirect to login page.
if ( !rootIsPresent(newRoute, routesThatDoNotRequireAuthentication) && !isAuthenticated ) {
$location.path('/login');
}
});
});
Seems that I've misunderstood the question and thought that all your routes are prefixed with either /protected
or /unprotected
(which, if you give it a thought, is really not that smart to do in most of the cases).
In this case, you can set an additional property when defining the routes in $routeProvider
:
$routeProvider
.when('/awesomePath', {
templateUrl: 'awesome-template.html',
controller: 'AwesomeController',
controllerAs: 'vm',
requireAuth: true // add the property that defines a route as protected or unprotected
})
And now, in your $routeChangeStart
handler function, you check whether the route user is going to is protected or not:
$rootScope.$on('$routeChangeStart', function () {
// Get the authentication status of a user
var isAuthenticated = authenticationService.isAuthenticated();
var newRoute = $location.url();
// In a controller, $route object has a 'current' property that
// holds route defined route properties, but here the 'current'
// property is null, so we need to get the $route object we
// need by using the $location.url()
if ( $route.routes[$location.url()].requireAuth && !isAuthenticated ) {
$location.path('/login');
}
});
Thus you don't need to hardcode your routes anywhere.
Upvotes: 1