w.brian
w.brian

Reputation: 17397

Redirect to route if user is not authenticated

I'm trying to cleanly implement a way to redirect the user to a login route if they're not logged in. I'm basing my solution off of another SO answer here that doesn't work out of the box. Here's my solution.

angular.module('myApp', ['ngResource', 'ngRoute'])
  .config(['$routeProvider', function ($routeProvider) {
    var requireAuthentication = function () {
        return {
            load: function ($q) {
                console.log('Can user access route?');
                if (g_isloggedIn === true) { // fire $routeChangeSuccess
                    var deferred = $q.defer();
                    deferred.resolve();
                    console.log('Yes they can!');
                    return deferred.promise;
                } else { // fire $routeChangeError
                    console.log('No they cant!');
                    return $q.reject("'/login'");
                }
            }
        };
    };

    $routeProvider
        .when('/some_page_that_requires_authentication', {
            templateUrl: '/views/secret.html',
            controller: 'secretCtrl',
            resolve: requireAuthentication()
        })
        .when('/anybody_can_see_me', {
            templateUrl: '/views/public.html',
            controller: 'publicCtrl',
        });
}]);

My question is, where can I listen on the $routeChangeError event so that I can redirect the route? I tried doing it in a directive, but could never get the event to fire. I can't put it into a controller, because it won't load if the promise is rejected. Any thoughts?

Upvotes: 5

Views: 10246

Answers (3)

Kraken
Kraken

Reputation: 5860

I'm sure you're well past this issue, but for those looking for answers now, here's my two cents.

The only thing you are missing here is what happens when the promise is rejected. You'll want to do this with HTTP interception. You put a listener on routeChangeError, and redirect there. https://docs.angularjs.org/api/ng/service/$http (scroll down to interceptors section)

Upvotes: 0

wiherek
wiherek

Reputation: 1923

Is there a reason why you shouldn't redirect the user from inside the function? This works fine for me, it doesn't load the controller / view if the promise is not resolved.

I modified the function like this:

var requireAuthentication = function () {
    return {
        load: function ($q, $location) {
            console.log('Can user access route?');
            var deferred = $q.defer();
            deferred.resolve();
            if (g_isloggedIn === true) { // fire $routeChangeSuccess
                console.log('Yes they can!');
                return deferred.promise;
            } else { // fire $routeChangeError
                console.log('No they cant!');
                $location.path('/login');

                // I don't think this is still necessary:
                return $q.reject("'/login'");
            }
        }
    };
};

Upvotes: 3

Jens
Jens

Reputation: 3412

You might find some help in this question: AngularJS: Understanding $rootScope.$on('$routeChangeSuccess

Generally I feel that using "resolve" for ensuring authentication is a bit odd, but there are not much better ways, I would suggest adding some services etc. Which is besides the point.

Finally, other routing solutions like https://github.com/dotJEM/angular-routing may provide you with a better degree of control.

Upvotes: 0

Related Questions