27

I'm working on a new Angular2 app, and I was wondering how would you manage routes accessible to certain roles and permissions to create, edit, and delete items for certain roles.

I want to know how do you solve the problem such this:

  • How do you manage access to some UI elements? How does the app know to show or hide it? Do you use single service for this? Or do you create different conditions for the different place in your app?

  • How do you manage your routing? Do you use CanActivate, CanActivateChild, CanLoad and etc? Do you build a single guard service for all routes or make different services for different modules or component?

  • And last question. What is the best way to divide the app then you can sell it like a CMS? I mean how can we realize possibility to load some other modules from the market for example, and add it in your app?

How do you solve the similar problem?

Any guidance, experience, or pointers to material covering these topics is greatly appreciated. Thanks in advance.

tekin
  • 145
  • 4
  • 15
Roman Skydan
  • 5,478
  • 4
  • 19
  • 39
  • 4
    This question is far too broad for SO's Q/A format. There are entire chapters of books written that cover how to solve these problems. In short: routes, auth guards, and modules. – AJ X. Oct 05 '17 at 21:57
  • @axlj yes I understand it. And you right. But how you know so many people don't like read books now. And more people who have good ideas about some questions will never write a book about it. But maybe if all these people to write some little answer then we will have a place where people who don't like read a book can read about this. And add something of their own :) – Roman Skydan Oct 05 '17 at 22:11
  • I hear you, and I prefer creating over reading long books as well. Unfortunately, a complete answer to this specific question would yield just that! – AJ X. Oct 05 '17 at 22:17

3 Answers3

25

As mentioned in the comments to your question, a complete answer is beyond the scope of a SO question/answer, and so you may find your question closed in the near future for that reason, but here's some quick suggestions for you to explore further on your own:

  • Get the user's permissions from the server during/after login via http/https. Store these permissions somewhere that makes sense for your app, perhaps in a service. If you're using JWT, the permissions can be returned in the JWT token.

  • To simplify things, only deal with permissions on the client. Roles are for the server code to figure out what permissions the user has. No need to muck things up by conflating roles with permissions on the client.

  • Protect routes with auth guards

  • Protect individual UI elements with *ngIf or ngSwitch/*ngSwitchCase

  • Dynamic Loading is a big topic area - go read about it - lots of resources on the web. However, as far as I know, while you can lazily load modules, they must be known to the application at compile-time. I may be mistaken, but I don't think that you can just load anything you want at runtime.

GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67
12

So I had to implement something like this on an application I worked out, this is how I handled it.

I created a auth service, this contained a method that checked if the user had a management role:

auth.service.ts

public isManager(): boolean {
    let isManager = false;
    let user = this.getUserToken();
    //Stored my allowed groups in a config file, comma separated string
    let allowedGroups = AuthenticationParams.filters.split(',');
    let userGroups: any;
    if (user !== null && user !== undefined) {
      try {
        let userGroups: any = user.role;
        if (userGroups !== undefined && userGroups !== null && userGroups.length > 0) {
          try {
            userGroups.forEach((e: any) => {
              if (allowedGroups.indexOf(e) > -1) {
                isManager = true;
              }
            });
          } catch (e) {
            if (allowedGroups.indexOf(userGroups) > -1) {
              isManager = true;
            }
          }
        }
      } catch (e) {
        isManager = false;
      }
    }
    return isManager;
}

public getUserToken(): any {
    return localStorage.getItem('jwtTokenName');
}

I created an auth guard as follows:

guard.component.ts

import { Injectable, OnInit } from '@angular/core';
import { CanActivate, CanActivateChild } from '@angular/router';
import { Router } from '@angular/router'; 
import { AuthenticationService } from '../services/helper/security/auth.service';

@Injectable()
export class GuardComponent implements CanActivate {

  constructor(private authenticationService: AuthenticationService, private _router: Router) {
  }

  canActivate() {
    let isManager: boolean = this.authenticationService.isManager();
    if (!isManager) {
      this._router.navigate(['unauthorized']);
    }
    return isManager;
  }
}

guard.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { GuardComponent } from './guard.component';

@NgModule({
  declarations: [],
  imports: [ CommonModule ],
  exports: [],
  providers: [ GuardComponent ],
})
export class GuardModule { }

I then used the guard for my route that handles navigation to the admin section

app-routing.module.ts

{ path: 'management', component: AdminComponent, canActivate: [GuardComponent] }

On my navigation bar I just call the isManager method and stored that on a variable and use that to determine whether or not the management link needs to be displayed or not.

navbar.component.ts

public isManager: boolean = false;

ngOnInit(): void {
    this.isManager = this.authenticationService.isManager();
}

navbar.component.html

<li [routerLinkActive]="['active']" *ngIf="isManager"><a [routerLink]="['management']">Management Portal</a></li>

I've had to remove some data from each method, but this will give you the basic idea. Hopefully this helps.

DerZyklop
  • 3,672
  • 2
  • 19
  • 27
Wesley Coetzee
  • 4,768
  • 3
  • 27
  • 45
  • 1
    So if we have many roles ~30, we would need to create `isRole()` for all of them? – DevEng Apr 05 '18 at 13:45
  • It would depend on what roles need to access what pages. if 10 roles can access 1 page then just check for those roles before accessing that page for example. – Wesley Coetzee Apr 05 '18 at 18:25
8

This question is quite broad and i don't thing you can cover it easily in this answer. There are basically three things attached to it

  • Routing
  • Guards
  • Modules

You need to have single guard module that will check for the entire app and all the sub routes will be a children for the guard route . In short it will act like a global guard for your whole application . And Your routing will be covered in short . More on Guards

And now talking about modules you need to split everything into common and featured modules and reuse the modules or use it independently. This will help you sell it like a CMS . More on Modules .

Note - This is not a exact answer but a gist to your problem

Rahul Singh
  • 19,030
  • 11
  • 64
  • 86