Angular ui-router: how to prevent access to a state

Hello I'm new to angularJS and have been trying to prevent access to certain states based on user critera.

This, from ui-router's FAQ describes exactly what I want to do, but I cant get it to work properly. What do I need to but in the data object exactly to accomplish this?

(I saw someone throwing in "true" on some blog post tutorial and using it like how I have, but that doesnt seem to work because I get an error that says needAdmin is not defined)

Here is my code:

angular.module('courses').config(['$stateProvider',
    function($stateProvider) {
        // Courses state routing
        $stateProvider.
        state('listCourses', {
            url: '/courses',
            templateUrl: 'modules/courses/views/list-courses.client.view.html'
        }).
        state('createCourse', {
            url: '/courses/create',
            templateUrl: 'modules/courses/views/create-course.client.view.html',
            data: {
                needAdmin: true
            }
        }).
        state('viewCourse', {
            url: '/courses/:courseId',
            templateUrl: 'modules/courses/views/view-course.client.view.html'
        }).
        state('editCourse', {
            url: '/courses/:courseId/edit',
            templateUrl: 'modules/courses/views/edit-course.client.view.html',
            data: {
                needAdmin: true
            }
        });     

    }
]);


angular.module('courses').run(['$rootScope', '$state', 'Authentication', function($rootScope, $state, Authentication) {
  $rootScope.$on('$stateChangeStart', function(e, to) {

    var auth = Authentication;

    console.log(auth.user.roles[0]);
    if (to.data.needAdmin && auth.user.roles[0] !== 'admin') {
      e.preventDefault();
      $state.go('/courses');
    }

  });
}]);

Answers:

Answer

If a state has no data, then to.data is undefined. Try this:

if (to.data && to.data.needAdmin && auth.user.roles[0] !== 'admin') {
Answer

The best way I have found to do this uses resolve:

    $stateProvider.        
    state('createCourse', {
        url: '/courses/create',
        templateUrl: 'modules/courses/views/create-course.client.view.html',
        resolve: {
           security: ['$q', function($q){
               if(/*user is not admin*/){
                  return $q.reject("Not Authorized");
               }
           }]
        }
    });

This will trigger an error, preventing the user from accessing this state if they are not allowed.

If you need to show an error, or send the user to a different state, handle the $stateChangeError event:

$rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error){

    if(error === "Not Authorized"){
        $state.go("notAuthorizedPage");
    }

If you want to check for admin access on all states, you could use a decorator to add the resolve to all states. Something like this:

$stateProvider.decorator('data', function(state, parent){
    var stateData = parent(state);
    var data = stateData.data || {};

    state.resolve = state.resolve || {};
    if(data.needAdmin){
       state.resolve.security = ['$q', function($q){
               if(/*user is not admin*/){
                  return $q.reject("Not Authorized");
               }
           }];
    return stateData;
});

I implemented something like this for my current application. If user is not logged in, we forward the user to a login form. If non-admin user attempts to hit any admin state, we forward to an error page.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.