How do I check for login or other status before launching a route in Angular with routeProvider?

All we need is an easy explanation of the problem, so here it is.

Let’s say I have 4 routes – 2 require the user to be logged in, 2 do not. My app init looks like:

        $routeProvider.when('/open1',{templateUrl:'/open1.html',controller:'Open1'});
        $routeProvider.when('/open2',{templateUrl:'/open2.html',controller:'Open2'});
        $routeProvider.when('/secure1',{templateUrl:'/secure1.html',controller:'Secure1'});
        $routeProvider.when('/secure2',{templateUrl:'/secure2.html',controller:'Secure2'});

Routes /open1 and /open2 are open to all, while routes /secure1 and /secure2 require the user to be logged in and, if not, take some action, e.g. redirect to login or launch a warning. I can determine the user’s state by using my Auth service and calling, e.g., Auth.isLogin(). So the result would be:

  • going to /open1 and /open2 always go to the template and controller declared above
  • if Auth.isLogin() returns true, /secure1 and /secure2 go to the above-declared template and controller
  • if Auth.isLogin() returns false, /secure1 and /secure2 take some other action, e.g. $location.path('/login')

I could put logic in the Secure1 and Secure2 controllers that checks, but that is repetitive and mixes up responsibilities, makes them harder to test, etc.

Is there a way that I can use the $routeProvider to declare, “check this route and this route and if not, redirect”? I was thinking of using resolve somehow, but not quite sure how to work it in (docs on resolve are not very clear, and few helpful examples).

EDIT:

based on the answers below, it appears there are three philosophies for doing this:

The 2nd option is what the two answerers have suggested.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

As in my comments above, there are 3 different paths (plus the ability to use a directive if you want to control it from within html templates). I ended up following

https://midgetontoes.com/angularjs-check-user-login/

which essentially is as follows:

$routeProvider.when('/secure', {
    templateUrl: '/secure.html', 
    controller: 'Secure',
    resolve:{
        loggedIn:onlyLoggedIn
    }
 });

And then onlyLoggedIn:

var onlyLoggedIn = function ($location,$q,Auth) {
    var deferred = $q.defer();
    if (Auth.isLogin()) {
        deferred.resolve();
    } else {
        deferred.reject();
        $location.url('/login');
    }
    return deferred.promise;
};

Simple, works like a charm. If I ever need a directive, I will pull this piece into a service.

Method 2

This blog post deals with user authentication in AngularJS using directives.

The $route service emits $routeChangeStart before a route change.

If you don’t use directives, you can catch that event by calling app.run (you can place it after the code where you define the routes [app.config]). For example:

For full disclosure I use ui.router and this is an adapted code from $stateChangeStart I use in my app

var app = angular.module('app');

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/open1',{templateUrl:'/open1.html',controller:'Open1'});
    $routeProvider.when('/open2',{templateUrl:'/open2.html',controller:'Open2'});
    $routeProvider.when('/secure1',{templateUrl:'/secure1.html',controller:'Secure1'});
    $routeProvider.when('/secure2',{templateUrl:'/secure2.html',controller:'Secure2'});
}]);

app.run(['$rootScope', '$location', 'Auth', function($rootScope, $location, Auth) {
    $rootScope.$on('$routeChangeStart', function(event, currRoute, prevRoute){
        var logged = Auth.isLogin();

        //check if the user is going to the login page
        // i use ui.route so not exactly sure about this one but you get the picture
        var appTo = currRoute.path.indexOf('/secure') !== -1;

        if(appTo && !logged) {
            event.preventDefault();
            $location.path('/login');
        }
    });
}]);

Method 3

I had the same problem and I did it this way:

var app = angular.module('myModule',["ui-bootstrap"]);

And then listen for a locationchange in the app (this will also trigger onEnter of a page)

app.run(function ($rootScope, $location, $cookieStore) {
 $rootScope.$on("$locationChangeStart", function (event, next, current) {
    //Here you can check whatever you want (servercall, cookie...)
 });
}

I Hope this helps!

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply