Search code examples
javascriptauthenticationangularjsangularjs-routingangularjs-authentication

AngularJS | handle routing before they load


I wish to create a simple authentication check for my routes by external service.

I define the access requirements on the route object:

$routeProvider
    .when('/', {
        templateUrl: 'src/app/views/index.html',
        controller: 'indexCtrl',
        authenticated: true
    })
    .when('/login', {
        templateUrl: 'src/app/views/login.html',
        controller: 'loginCtrl',
        anonymous:  true
    })
    .otherwise({
        redirectTo: '/'
    })
;

Then, I check if I have permission within the $routeChangeStart event.

$rootScope.$on('$routeChangeStart', function (event, next) {
    if(next.authenticated && !$myService.isLoggedin())
        $location.path("/login");
    else if(next.anonymous && $myService.isLoggedin())
        $location.path("/secured");
});

Actually, it works-
if the user in not authenticated it move him to the login page, if he is authenticated but the route is for anonymous users only it move them to another page, and etc..

BUT- this redirection actually happening after the controllers and the templates is load! And it cause my controller to do some unnecessary request to my REST API, even if I'm not authenticated.

How can I handle the route before they process?


Solution

  • My solution was combining $locationChangeStart and $routeChangeStart:

    $rootScope.$on('$locationChangeStart', function (event) {
        //If login data not available, make sure we request for it
        if($facebook.isConnected()==null) {
            $facebook.getLoginStatus();
            event.preventDefault();
            return;
        }
    
        var next=parseRoute().$$route;
        if(!Auth.loginCheck(next))
            event.preventDefault();
    });
    

    I copied parseRoute() from angular-route.js to parse the given URL to route..

    Then I build my login check handler(Auth.loginCheck) in a way that if it fail it return false.

    I also use $routeChangeStart to handle $route.reload() events, so now after every change within my authentication status I just do $route.reload():

    $rootScope.$on('$routeChangeStart', function (event, next) {
        Auth.loginCheck(next);
    });
    

    Finally I just make sure that this custom service is always will run by using simple run() method.

    Edit:

    We now using ngAuth, a module we designed to solve that exact problem(based on the answer I gave here before).

    At last, we developed a angular-module that solved this issue.. This module is based on the answer I published here before.

    Due the requests here, we published a beta release that works now: http://github.com/GoDisco/ngAuth

    Feel free to use it.