12

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?

brazorf
  • 1,943
  • 2
  • 32
  • 52

2 Answers2

14

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.

Liviu T.
  • 23,584
  • 10
  • 62
  • 58
  • This seems to be a good solution, but if user navigates to http://srv/sub-templates-dir/template1.html he's still able to load the template, though. Should this check be implemented server side? – brazorf Dec 22 '12 at 11:15
  • The implementation just checks for equality for a path, but you could implement a much complex checking system. I updated my answer. – Liviu T. Dec 22 '12 at 15:22
  • @LiviuT. just want to ask how will I be able to bypass the routeAuth, say the user just successfully authenticated the he should be able to view template1. How do I change the routeaccess from restricted to allowed?. – Wondering Coder Aug 26 '13 at 07:35
  • I suggest that the login functionality set a flag on a service then inject that service in the controller and check in the event listener something like (UserStatus.isLoggedIn || scope.routeAuth.allowed) – Liviu T. Aug 26 '13 at 20:46
0

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

Community
  • 1
  • 1
Mathew Berg
  • 28,625
  • 11
  • 69
  • 90