Angular UI Router is the de-facto solution for single page applications and flexible routing in angular. It has many useful features such as nested views and states that can help us write clean code.
A careful consideration on how we structure our application in nested states/views, and a thoughtful process of designing and structuring the state tree, can help us achieve a solid design and a clean architecture for our application.
We are going to see a brief example on how to use the nested states feature to implement an elegant solution for the security of an application.

Our Application Security Requirements

In a nutshell, we need to build an application that has the following requirements:

  1. The application has three security roles:
    • Read only role.
    • Editor role.
    • Admin role.
  2. Each role has access to his own pages and urls and cannot access pages of other roles.
  3. When a read only user try to access a URL for an admin, by typing the URL in the address bar, the application will refuse


This is a diagram to shows the hierarchical states and pages.
states


What Angular UI router can provide?

The main power in Angular UI Router is in its ability to nest states and views and share data between them.
From the library web site I quote:

Nested states and views have a hierarchical model, where state/views in the higher level share data with their child states/views , and sharing data will help with re-usability of the code by taking the commonality in the model and code into a higher states.

Parent states share with its children two main properties:

  • Resolved dependencies defined via resolve.
  • Custom data properties.

Implement user state

$stateProvider.state('user', {
    abstract: true,
    url: '/',
    template: '',
    data: {
        userToken : userToken;
    }
});

In the previous example, we added the user token to the data property of the top level state, which means in any child state we can access that user token with this syntax:

function controller($state){
    var userId = $state.current.data.userId;
}

By putting this important piece of the information in the top level state, then we can assure that anywhere in our application, either in the config code, or the controller code, we have access to this piece of the information.

And that was one method of using nested states to have a clean solution by sharing important data in the top-level states.

Implement the admin role state

Assuming we have a REST service called authService that has an action checkRole. And the REST service accepts two parameters:

  1. userId
  2. role name

The service will return a JavaScript promise which resolve successfully in case the user belong to that role, or reject if the user doesn’t belong to that role.
We can use this service as a resolve property of the admin state, like this.

$stateProvider.state('user.admin', {
    abstract: true,
    url: '/admin',
    resolve:{
        roleCheck:  function(authService, $state){
            // query the auth service to make sure that the user has admin access
            return authService.checkRole($state.current.data.userId, 'admin');
        }
}}

In the previous code, if the user didn’t belong to the role, then the promise will fail, which will prevent the Angular from moving to the state.
We used the resolve property of the state, to prevent moving to the state if the user doesn’t belong to the role.
The service when resolved can return back useful information for all the admin states, and pages.

This is another usage of nested states features that help build a clean solution, by using resolve to control the flow, and share data at the same time.

So, when the user will change the URL in the browser to point to an admin page, this resolve will check if the user has the permission ot move there or not and will move to that page if the user has the right to do that.

P.S: Please note that this client side code is not a real robust security solution, because a malicious user can easily hack it, and still we need a good security on the server side of the code.

Conclusion

We introduced how to use the Angular routing UI nested states, and views to show how to write a clean code implementing the security of the system.
Nested states and views can be used an a similar fashion to re-use and share the code between parts of the applications.
A good exercise is to think carefully on what the best way to represent the hierarchical states / urls that our applications is going to have, because a good decisions on structuring the state tree will help build a clean code.