How to hide templates with AngularJS ngView for unauthorized users?

All we need is an easy explanation of the problem, so here it is.

I have a basic PHP app, where the user login is stored in the HTTP Session. The app has one main template, say index.html, that switch sub-view using ngView, like this

<body ng-controller='MainCtrl'>
    <div ng-view></div>
</body>

Now, this main template can be protected via basic PHP controls, but i have sub-templates (i.e. user list, add user, edit user, etc.) that are plain html files, included from angular according to my route settings.

While i am able to check for auth what concern the request of http services, one user is able to navigate to the sub-template url and access it. How can i prevent this from happen?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I would create a service like this:

app.factory('routeAuths', [ function() {
  // any path that starts with /template1 will be restricted
  var routeAuths = [{
      path : '/template1.*',
      access : 'restricted'
  }];
  return {
    get : function(path) {
      //you can expand the matching algorithm for wildcards etc.
      var routeAuth;
      for ( var i = 0; i < routeAuths.length; i += 1) {
        routeAuth = routeAuths[i];
        var routeAuthRegex = new RegExp(routeAuth.path);
        if (routeAuthRegex.test(path)) {
          if (routeAuth.access === 'restricted') {
            return {
              access : 'restricted',
              path : path
            };
          }
        }
      }
      // you can also make the default 'restricted' and check only for 'allowed'
      return {
        access : 'allowed',
        path : path
      };
    }
  };
} ]);

And in the main/root controller listen for $locationChangeStart events:

app.controller('AppController', ['$scope', '$route', '$routeParams', '$location', 'routeAuths',
  function(scope, route, routeParams, location, routeAuths) {
    scope.route = route;
    scope.routeParams = routeParams;
    scope.location = location;

    scope.routeAuth = {
    };

    scope.$on('$locationChangeStart', function(event, newVal, oldVal) {
      var routeAuth = routeAuths.get(location.path());
      if (routeAuth.access === 'restricted') {
        if (scope.routeAuth.allowed) {
          event.preventDefault();
        }
        else {
          //if the browser navigates with a direct url that is restricted
          //redirect to a default
          location.url('/main');
        }
        scope.routeAuth.restricted = routeAuth;
      }
      else {
        scope.routeAuth.allowed = routeAuth;
        scope.routeAuth.restricted = undefined;
      }
    });

}]);

Demo:

References:

UPDATE:

In order to fully prevent html template access then it’s best done on the server as well. Since if you serve the html from a static folder on server a user can access the file directly ex: root_url/templates/template1.html thus circumventing the angular checker.

Method 2

If you want to block them from going to that page create a service: http://docs.angularjs.org/guide/dev_guide.services.creating_services

This service can be dependency injected by all your controllers that you registered with the routeParams.

In the service you can would have a function that would check to see if the person is logged in or not and then re-route them (back to the login page perhaps?) using http://docs.angularjs.org/api/ng.$location#path. Call this function in each of the controllers like so:

function myController(myServiceChecker){
    myServiceChecker.makeSureLoggedIn();
}

The makeSureLoggedIn function would check what current url they’re at (using the $location.path) and if it’s not one they’re allowed to, redirect them back to a page that they are allowed to be.

I’d be interested to know if there’s a way to prevent the routeParams from even firing, but at least this will let you do what you want.

Edit: Also see my answer here, you can prevent them from even going to the page:

AngularJS – Detecting, stalling, and cancelling route changes

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply