meanstacky
meanstacky

Reputation: 397

How to restrict routes with $routeProvider

In a MEAN app, I have an authService module with an Auth factory which contains an authFactory.isLoggedIn function:

// check if a user is logged in
    // checks if there is a local token
    authFactory.isLoggedIn = function() {
        if (AuthToken.getToken()) 
            return true;
        else
            return false;   
    };

So I thought I could use this with the resolve property of $routeProvider like this:

var MyModule = angular.module('app.routes', ['ngRoute']);

MyModule.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {


    $routeProvider

        // route for the home page
        .when('/', {
            templateUrl : 'app/views/pages/home.html'
        })

        // login page
        .when('/login', {
            templateUrl : 'app/views/pages/login.html',
            controller  : 'mainController',
                controllerAs: 'login'
        })

        // register page
        .when('/register', {
            templateUrl: 'app/views/pages/register.html',
            controller: 'userCreateController',
            controllerAs: 'register'
        })

        // upload page
        .when('/upload', {
            templateUrl : 'app/views/pages/upload.html',
            controller: 'uploadController',
            controllerAs: 'userupload',
            resolve: function($q, $location) {
                var deferred = $q.defer();
                deferred.resolve();
                if (!Auth.isLoggedIn) {
                    $location.path('/login');
                }
                return deferred.promise;
            }

        })

        //logout
        .otherwise({redirectTo: '/'});

    $locationProvider.html5Mode(true);

}]);

Unfortunately this doesn't work to stop unauthenticated users accessing the upload page and I don't see any errors being reported. I have seen instances of simpler ways to do this eg:

.when('/upload', {
            templateUrl : 'app/views/pages/upload.html',
            controller: 'uploadController',
            controllerAs: 'userupload',
            isLoggedIn: true

        })

But that doesn't work either, which is a shame as it's far simpler.

Upvotes: 2

Views: 4421

Answers (3)

meanstacky
meanstacky

Reputation: 397

In the end I was determined to use the resolve property of $routeProvider so after experimenting with the solution on http://midgetontoes.com/blog/2014/08/31/angularjs-check-user-login I came up with:

var MyModule = angular.module('app.routes', ['ngRoute']);

MyModule.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {

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


    $routeProvider

        // route for the home page
        .when('/', {
            templateUrl : 'app/views/pages/home.html'
        })

        // login page
        .when('/login', {
            templateUrl : 'app/views/pages/login.html',
            controller  : 'mainController',
                controllerAs: 'login'
        })

        // register page
        .when('/register', {
            templateUrl: 'app/views/pages/register.html',
            controller: 'userCreateController',
            controllerAs: 'register'
        })

        // upload page
        .when('/upload', {
            templateUrl : 'app/views/pages/upload.html',
            controller: 'uploadController',
            controllerAs: 'userupload',
            resolve:{loggedIn:onlyLoggedIn}


        })

        //logout
        .otherwise({redirectTo: '/'});

    $locationProvider.html5Mode(true);

}]);

I am sure this isn't as good as the custom http interceptor as posited by @Dimitiri Algazin or as simple as the solution from @Pasan Ratnayake but it does fulfil my quest to use resolve. Thanks to @Dimitri and @Pasan anyway.

Upvotes: 1

Pasan Ratnayake
Pasan Ratnayake

Reputation: 495

There are multiple ways you could achieve this functionality.

Easiest would be to add a check similar to below code to each controller that you don't want your users to access.

// You could re-direct the user to a '401' state as well
if (!authFactory.isLoggedIn())
  $state.go('login');

Upvotes: 0

Dmitri Algazin
Dmitri Algazin

Reputation: 3456

Add custom http interceptor. This is not exact code, just algorithm, some syntax might missing:

.factory('myHttpInterceptor', function($q, $location, AuthToken) {

    function isLoggedIn() {
        return !!AuthToken.getToken();
    }

    function canRecover(response) {
        var status = response.status;
        var config = response.config;
        var method = config.method;
        var url = config.url;

        console.log("--->>> ", method, status, url);

        if (status == 401) {
            alert("401");
        } else if ( status == 403) {
            alert("403");
        } else if (status == 404) {
            alert("404");
        } else if (status == 405) {
            alert("405");
        } else if (status == 500) {
            alert("500");
        } else {
        }
        return response;
    }

    return {
        // optional method
        'request': function(config) {
            if (isLoggedIn()) {
                return config;
            } else {
                $location.path('login');
            }
        },

        // optional method
        'response': function(response) {
        // do something on success
        return response;
        },

        // optional method
        'requestError': function(rejection) {
            return $q.reject(canRecover(rejection));
        },

        // optional method
        'responseError': function(rejection) {
            return $q.reject(canRecover(rejection));
        }
    };
})
.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
}])

Upvotes: 0

Related Questions