Toggle Menu

Insights / Digital Service Delivery / Building Scalable and Beautiful AngularJS Apps (Part 6): Navigation Lifecycle, Authentication Hooks and Role Based Navigation

April 05, 2017

Building Scalable and Beautiful AngularJS Apps (Part 6): Navigation Lifecycle, Authentication Hooks and Role Based Navigation

6 mins read

Doguhan Uluca was a speaker at ng-conf 2017, where he talked about Do More with Less JavaScript. Check out the full talk. For more about conference related materials visit TheJavaScriptPromise.com.

First things first: Running code is far more valuable than any blog post. So, launch the demo site here, check out the source code on GitHub and pull the Docker image without delay: docker pull duluca/angular1.5-starter

Role Based Navigation

Angular Starter comes with built-in role-based navigation to demonstrate important concepts around user caching, utilizing authentication information during navigation and showing/hiding of navigational elements based on user roles.

The starter app has a dummy authentication module under app/services/auth, which authenticates any @test.com address successfully and fails any other input. Any password, so long as it meets the length requirement, will work. All users by default will have the user role, which you can observe on the Account page located at app/routes/about.

Login by including the word admin in the e-mail address, like [email protected] and your user account will have an admin role. Admins are allowed to see the Admin dashboard link on the SideNav, but even if a regular user had the route that is linked from the SideNav, they wouldn’t be able to view the page, because we are leveraging ngComponentRouter’s lifecycle events.

Cache, auth and account services work together to allow for role based navigation. auth provides a dummy authentication service, and results of the login attempt is cached by the cache service. account uses cache and auth services to hide away implementation details from the rest of the app. In addition, account demonstrates how profile information or account details can be added on to authentication information after the initial call.

Authentication services need to be performant and caching is an important part of any authentication strategy, especially on Angular. To make components and link display or hide properly, we leverage binding to functions, like vm.isAuthenticated() on SideNav. This allows for lazy and asynchronous loading of authentication information and will ensure viewModel doesn’t incorrectly cache the wrong authentication information, delegating that responsibility to the account service. Strictly following these patterns will keep our app maintainable as we add more views.

A side-effect of binding to functions is that the function will be called a lot. So the function can’t be tied to a live server call, after the initial authentication call. This is where the cache service provides us the information we need about the user in an efficient and reasonably secure manner.

You must remember that any client-side role-based navigation is merely a convenience. This is not meant to secure your data. After all we ship all the code down to the user’s browser. They can inspect and read all our templates and client-side code. This means that every call made to the server should contain the necessary header information so that the user can be re-authenticated by the server and only then they are allowed to retrieve secure data.

We can’t trust client-side authentication and this is why password reset screens must be built with a server-side rendering technology so that we can be sure only the intended audience is interacting with your system.

Navigation Lifecycle

ngComponentRouter has four main lifecycle events:

  • $canActivate: A function that allows you to return a boolean or a promise if true will allow for navigation and reject on false.
  • $onActivate: A function that fires when the page is loading. The event gives us access to route params, so we can load information from services to be displayed on the page.
  • $canDeactivate: Can be used to prevent navigation away from a page.
  • $onDeactivate: Can be used to clean up resources on navigation event away from a page.

Using Angular Starter, login as an admin and open F12 Developer Tools, so you see the console logs. Now, navigate to https://ng15demo.thejavascriptpromise.com/ – /admin/dashboardTwo/notJustAdemo and observe router lifecycle events in action on the Admin dashboard, including $canActivate and $onActivate.

Now logout and navigate to the same URL again, and observe that you won’t be able to. As an additional exercise, login as a regular user and try to go to the URL again. You still won’t be able to navigate to the route.

This is possible because $canActivate, operating in tandem with account and cache is disallowing the navigation request based on your authentication information.

Route Parameters

You can navigate by using ng-link, or $rootRouter with or without parameters.

If you can configure a route to a component like { path: ‘/about’, component: ‘about’, name: ‘About’ } and use ng-link=”[‘/About’]” to navigate to it through an <md-button&gt; or <a> tag.

Similarly, you can configure a route that requires a parameter to navigate to like { path: ‘/dashboardTwo/:someParam’, component: ‘dashboardTwo’, name: ‘DashboardTwo’ } and navigate to from code with $rootRouter.navigate([‘/Admin/DashboardTwo’, { someParam: ‘notJustAdemo’}]).

Note that in both cases, you are passing an array in to the router. In the latter case, you’re including an object that defines the required parameters. You can use either method in templates with binding and ng-link or in code with $rootRouter.

Also note that, you must prefix /Admin to DashboardTwo’s route, because it is a child route of the admin child route.

You can access the route parameter on the $onActivate function like vm.$routerOnActivate = function (toRoute) {

console.log(‘onactivate: ‘ + toRoute.params.someParam)

}

More component router samples can be found here.

BYO Authentication and Hooks

Angular Starter provides a dummy authentication service with services/auth. You can bring your own authentication solution into the project. As long as you implement the login, logout, and isAuthenticated functions, the role-based authentication is going to continue to work.

I can recommend the Satellizer project, which provides token-based authentication for AngularJS leveraging JSON Web Tokens (JWT) and allowing integrations with social logins. If you’re looking for a hosted solution Auth0 is a good provider.

Start Today

As German poet Goethe puts it, “what is not started today is never finished tomorrow.” Here’s the code on GitHub. Fork it, create issues with it, otherwise just clone it and use it. Start today.

If you have any questions, ask them on Twitter @duluca.

You Might Also Like

Resources

Simplifying Tech Complexities and Cultivating Tech Talent with Dustin Gaspard

Technical Program Manager, Dustin Gaspard, join host Javier Guerra, of The TechHuman Experience to discuss the transformative...

Resources

How Federal Agencies Can Deliver Better Digital Experiences Using UX and Human-Centered Design

Excella UX/UI Xpert, Thelma Van, join host John Gilroy of Federal Tech Podcast to discuss...