3

I'm trying to build Role-Permissions system that I want to initialize on root state resolve:

 $stateProvider
  .state('common', {
    resolve:{
      user: function(AclService, UserService) {
        UserService.getCurrent().then((currentUser) => {
          AclService.initialize(currentUser);
        });
      }
    }
  })

and check permissions each time on $stateChangeStart:

$rootScope.$on('$stateChangeStart', ($event, toState) => AclService.interceptStateChange($event, toState));

but I faced a problem that first $stateChangeStart was fired before resolve, so permissions were not initialized yet.

What would you recommend in such situation?

Stepan Suvorov
  • 25,118
  • 26
  • 108
  • 176

2 Answers2

0

You could do that in your app's run function. Here is a trimmed down version of how I load auth data up front.

(function() {

    "use strict";

    angular
        .module("myModule", [ //dependencies here...]);

    angular
        .module("myModule")
        .run(run);

    run.$inject = ["$rootScope", "$state", "authService"];

function run($rootScope, $state, authService) {

    authService.fillAuthData(); //front load auth stuff here...

    $rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {

        var isPublic = (toState.data && toState.data.isPublic && toState.data.isPublic === true);
        var requiredRole = (toState.data && toState.data.requiredRole) ? toState.data.requiredRole : null;
        var authorized = isPublic || authService.isUserInRole(requiredRole);

        if (authService.authentication.isAuth || isPublic) {

            //if the user doesn't have the requisite permission to view the page, redirect them to an unauthorized page
            if (!authorized) {
                event.preventDefault();
                $state.go("unauthorized");
                return;
            }

        } else {

            event.preventDefault();
            $state.go("login");
            return;
        }
    });
}

})();

A state definition may look like this:

.state("someState", {
    url: "/someState",
    templateUrl: "my/folder/file.html",
    data: {
        pageTitle: "Some Page",
        isPublic: false,
        requiredRole: "Admin"
    }
})
BBauer42
  • 3,549
  • 10
  • 44
  • 81
  • I'm getting use permissions from server asynchronously, I don't see it in your solution – Stepan Suvorov Feb 26 '16 at 14:06
  • That happens inside authService.fillAuthData(). – BBauer42 Feb 26 '16 at 14:09
  • but how could you be sure that it will be resolved before such sync check - if (authService.authentication ? – Stepan Suvorov Feb 26 '16 at 14:16
  • Inside .fillAuthData I'm using var deferred = $q.defer(); and deferred.resolve(apiResponse) to ensure the promise resolves. Have a [look at $q here](https://docs.angularjs.org/api/ng/service/$q). – BBauer42 Feb 26 '16 at 14:23
  • Or have a look [here](http://stackoverflow.com/questions/26750814/how-to-make-synchronous-http-request-in-angular-js). – BBauer42 Feb 26 '16 at 14:26
  • "deferred.resolve(apiResponse) to ensure the promise resolves." - you resolve it yourself, but it does not mean when you are doing ajax request that you know it. sync ajax like solution looks tooo ugly for me – Stepan Suvorov Feb 26 '16 at 14:38
0

You shouldn't do some auth logic in state resolves. Better approach is to set listener for $stateChangeStart event in angular.run function:

angular.module('yourModule', [])
    .run(['$rootScope', 'principal', '$state', function ($rootScope, principal, $state) {
        var firstOpen = true;
        $rootScope.$on('$stateChangeStart', function(event, toState, toParams) {
            if (!principal.isAuthenticated() && firstOpen) {
                firstOpen = false;
                event.preventDefault();
                principal.checkAuthentication().then(function() {
                    $state.go(toState, toParams);
                });
            } else if (principal.isAuthenticated() && toState.name === 'login') {
                event.preventDefault();
                // Do some stuff here, for example, redirect to main page
            }
        });
    }
]);
Boris Parnikel
  • 863
  • 1
  • 7
  • 15