angularjs authentication using $locationChangeStar

2019-09-16 04:06发布

问题:

I'm authenticating an angular app code given below, Basically I'm checking token from backend called if token is valid then we can allow users to view allowed page.

It's working somewhat but problem is when I'm going to /jobs page is somewhat loading then redirecting to login page but i don't want to show jobs page initially for few seconds it should be redirect quickly or it will not load jobs page.

In app.js

    var app = angular.module('ttt', ['ui.router', 'ui.bootstrap', 'ngResource', "ngStorage", "ngProgress", "ngCookies", 'angular-jwt', 'ngLodash','tagged.directives.infiniteScroll']);
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', "$httpProvider", function ($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider) {
    $locationProvider.html5Mode(true);
    $urlRouterProvider.otherwise(function ($stateParams) {
        console.log("val check", $stateParams, window.location);
        window.location.href = "/undefined";

    });
    $stateProvider.state("jobs", {
        url: "/jobs",
        templateUrl: "views/dashboard.html",
        controller: "JobController as JobCtrl",
        resolve : {
            formInfo : ["AuthService",function (AuthService) {
                return AuthService.getFormInfo();
            }]
        }
    }).state("undefined", {
        url: "/undefined",
        templateUrl: "views/pagenotfound.html",
        bodyClass: "errors errors-404 errors-centered"
    }).state("login", {
        url: "/login",
        templateUrl: "views/login.html",
        controller: "LoginController as LoginCtrl",
        resolve : {
            formInfo : ["AuthService",function (AuthService) {
                return AuthService.getFormInfo();
            }]
        }
    })
}]);
app.run(['$rootScope', 'ngProgressFactory', '$state', '$compile', '$location', '$cookies', 'jwtHelper','AuthService', function ($rootScope, ngProgressFactory, $compile, $state, $location, $cookies, jwtHelper,AuthService) {
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams, options) {
        $rootScope.progressbar = ngProgressFactory.createInstance();
        $rootScope.progressbar.start();
        $rootScope.location = $location;
    });

  var authPreventer =  $rootScope.$on('$locationChangeStart', function (event, toState, toParams, fromState, fromParams, options) {

        var notCheckRoute = ["/undefined", "/signin", "/login"];
        //event.preventDefault();
         if(notCheckRoute.indexOf($location.path()) !== -1){
            AuthService.checkPermission()
            .then(function(data) {
                //event.preventDefault();
                if(data.active){
                    $location.path('/home'); 
                }else{
                    $location.path('/login');
                }
            });
         }else{
             //event.preventDefault();
            AuthService.checkPermission()
            .then(function(data) {
                if(!data.active){
                    $location.path('/login'); 
                }else{
                    //$location.path('/jobs'); 
                }
            });
         }
    });

    $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
        $rootScope.progressbar.complete();
        $rootScope.bodyClass = toState.bodyClass;
    });

    $rootScope.$on('$stateChangeError', function (event) {
        //$state.go('undefined');
    });
}]);

In service

    app.service('AuthService',['jwtHelper','$cookies','$location','$window','$http','$q',function (jwtHelper,$cookies,$location,$window,$http,$q) {

    this.login = function (token){
        var payload = jwtHelper.decodeToken(token);
    };

    this.logout = function (data) {

    };


var validatetoken = undefined;

this.checkPermission = function () {
    if (!validatetoken) {

        // create deferred object using $q
        var deferred = $q.defer();

        // get validatetoken form backend
        $http.post('/api/validatetoken', {token: $cookies.get('token')})
          .then(function(result) {
            // save fetched validatetoken to the local variable
            validatetoken = result.data;
            // resolve the deferred
            deferred.resolve(validatetoken);
          }, function(error) {
            validatetoken = error;
            deferred.reject(error);
          });
        // set the validatetoken object to be a promise until result comeback
        validatetoken = deferred.promise;
      }

      return $q.when(validatetoken);
}

    this.getFormInfo = function () {
         return $http.get("/api/getloginurl");
    }


}]);

回答1:

i don't want to show jobs page initially for few seconds it should be redirect quickly or it will not load jobs page.

When using the ui-router, avoid putting code in the $locationChangeStart block. This will cause conflicts with ui-router operation.

To prevent the jobs page from loading, check the authorization in the resolver for the state.

$stateProvider.state("jobs", {
    url: "/jobs",
    templateUrl: "views/dashboard.html",
    controller: "JobController as JobCtrl",
    resolve : {
        formInfo : ["AuthService",function (AuthService) {
            return AuthService.getFormInfo();
        }],
        //CHECK permission
        permission: ["AuthService", function (AuthService) {
            return AuthService.checkPermission()
              .then(function(data) {
                if(!data.active){
                    return data 
                } else {
                    //REJECT if not authorized
                    throw "Not Authorized";
                };
            }).catch(function(error) {
                console.log("ERROR");
                throw error;
            });
        }];
    }
})

By rejecting the resolve, the state change will be aborted and the page will not load.


Update

I can put in resolve state but if we have more state for example we have 50 different URL then every time do we have to put permission:

["AuthService", function (AuthService) { 
       return AuthService.checkPermission() 
         .then( function(data) { 
           if(!data.active){ 
               return data
           } else { 
               //REJECT if not authorized throw "Not Authorized";
           }; 
       }).catch( function(error) { 
           console.log("ERROR");
           throw error;
       });

All of that code can be re-factored into a service:

app.service("permissionService",["AuthService", function (AuthService) { 
    this.get = function () {
       return AuthService.checkPermission() 
         .then( function(data) { 
           if(!data.active){ 
               return data
           } else { 
               //REJECT if not authorized 
               throw "Not Authorized";
           }; 
       }).catch( function(error) { 
           console.log("ERROR");
           throw error;
       });
    };
}]);

Then use it in each resolver:

        //CHECK permission
        permission: ["permissionService", function (permissionService) {
            return permissionService.get();
        }];

By re-factoring the code, the resolver can be greatly simplified.