angularjs redirect to login page if not authenticated with exceptions

29,420

Finally figured out how to solve it using resolve.

first of all I completely removed the interceptor I was using before. then I made a function inside my Routing .config to use with every resolve for the authentication. finally to handle my resolve I'm using $stateChangeError to redirect to the login state

the Routing Config

.config(function ($stateProvider, $urlRouterProvider) {

    // function to check the authentication //
    var Auth = ["$q", "authService", function ($q, authService) {
        authService.fillAuthData;
        if (authService.authentication.isAuth) {
            return $q.when(authService.authentication);
        } else {
            return $q.reject({ authenticated: false });
        }
    }];

    /* if the state does not exist */
    $urlRouterProvider
        .otherwise('/page-not-found'); 

    $stateProvider

        // state that allows non authenticated users //
        .state('home', {
            url: '/',
            templateUrl: '/Content/partials/home.html',
        })

        // state that needs authentication //
        .state('smo-dashboard', {
            url: '/dashboard',
            templateUrl: '/Content/partials/dashboard.html',
            resolve: {
                auth: Auth
            }
        })

        // errors //
         .state('page-not-found', {
             url: '/page-not-found',
             templateUrl: '/Content/partials/error/404.html'
         })

        // accounts //
        .state('login', {
            url: '/accounts/login',
            templateUrl: '/Content/partials/account/login.html'
        })

        // OTHER STATES //
    }
);

in the MainController

$scope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {
    $state.go("login");
});
Share:
29,420
FabioG
Author by

FabioG

A good product now is better than a perfect product never. #SOreadytohelp

Updated on July 09, 2022

Comments

  • FabioG
    FabioG almost 2 years

    EDIT: forgot to mention that i've been working with AngularJs for a week only, so if you see something you think should be changed for the better and is not related to the question itself feel free to tell me on the comments section.


    ok, so I have my authentication Controllers and providers which I won't show because they're irrelevant for the scope of the question. Then I have an interceptor to check if the user is authenticated when a Call is made. If so I set the Authentication header on the request to include the user's Token if not I redirect the user to the login page and don't even make the request to the server (obviously if someone bypasses this theres also an Authorize on the API).

    What I want is to add a few exceptions, meaning there are some pages I want to allow even if the user has no Auth Token. I'm able to this if it's a specific path, but I want to allow my 404 page to be accessed and it's in the Routing that I'm specifying .otherwise to go to the 404 page, how can I make so that my interceptor only redirects to login if it's not going to this page.

    The interceptor

    .factory('authInterceptorService', ['$q', '$location', 'localStorageService', function ($q, $location, localStorageService) {
    
        var authInterceptorServiceFactory = {};
    
        var authData = localStorageService.get('authorizationData');
    
        var _request = function (config) {
    
            config.headers = config.headers || {};
    
            if (authData) {
                config.headers.Authorization = 'Bearer ' + authData.token;
            } else if ($location.path != '/accounts/login' && $location.path != '/accounts/register') {
                $location.path('/accounts/login');
            }
    
            return config;
        }
    
        var _responseError = function (rejection) {
            if (rejection.status === 401) {
                $location.path('/accounts/login');
            }
            return $q.reject(rejection);
        }
    
        authInterceptorServiceFactory.request = _request;
        authInterceptorServiceFactory.responseError = _responseError;
    
        return authInterceptorServiceFactory;
    }])
    

    and in my Routing

     $urlRouterProvider.otherwise('/page-not-found');
    
     $stateProvider
         (...)//rest of the states
    
         .state('page-not-found', {
             url: '/page-not-found',
             templateUrl: '/Content/partials/error/404.html',
             data: {
                 displayName: false
             }
         })
    
         (...)//rest of the states
    

    I tried to add '/page-not-found' to my if but it won't work as expected because by the time the location is checked for the first time it's still not redirected.

    edit As sugested by charlietfl I'm now trying to use resolve but it's not even passing my function.

    I removed this code from my interceptor:

    else if ($location.path != '/accounts/login' && $location.path != '/accounts/register') {
        $location.path('/accounts/login');
    }
    

    and add a new service to the authentication module:

    .service('authCheckService', ['$http', '$q', 'localStorageService', function ($http, $q, localStorageService) {
        var self = {
            'onlyLoggedIn': function ($state, $q) {
                var deferred = $q.defer();
                var authData = localStorageService.get('authorizationData');
                console.log(authData);
                if (authData) {
                    deferred.resolve();
                } else {
                    deferred.reject();
                    $state.go('login');
                }
                return deferred.promise;
            }
        }
    
        return self;
    }]);
    

    and i'm trying to call it as:

    .state('smo-dashboard', {
            url: '/dashboard',
            templateUrl: '/Content/partials/dashboard.html',
            resolve: authCheckServiceProvider.onlyLoggedIn
    })
    

    notice that i'm trying to log authData var to check if it's working but it isn't and there's no error on the console also.

  • FabioG
    FabioG over 8 years
    what I want is to have a 401 status response for some pages, even if there is no call to the server. Meaning I have a dashboard page which is only a partial-view with no calls to the API itself and I want to restrict it to authenticated users