Search code examples
angularangular-routingangular-routerangular-router-guards

Role based system in Angular


I would like to ask, how I can create the role based system in Angular. In my application, I have created the class app-routing.ts, where i would like to define

  • ClientComponent can open only the authorizated user with role client
  • AssistantsComponent can open only the authorizated user with role admin
const routes: Routes = [
  { path: '', component: AuthComponent},
  { path: 'assitants', component: AssitantsComponent , canActivate: [AuthGard]},
  { path: 'client', component: ClientComponent, canActivate: [AuthGard]}
]

The authorization is solved in AuthGard.ts:

export class AuthGard implements CanActivate{

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
  
     const accessToken = localStorage.getItem(AuthGard.LOCAL_STORAGE_ACCESS_TOKEN)
     if(!!accessToken){
         return true
     }else{
         return this.router.createUrlTree(['/auth'])
     }
  }
    
}

Question: Is it possible to use some general method, how i can solved this role access?

thank you very much


Solution

  • I've done it as following - assuming that the role of the user is stored in the JWT.

    I defined an enum with all the roles:

    export enum ROLE_LIST_ENUM {
       "ADMIN" = "ADMIN",
       "CLIENT" = "CLIENT"
    }
    

    Then, I added the role(s) needed to each route to be activated :

    const routes: Routes = [
      { path: '', component: AuthComponent},
      { path: 'assitants', 
        component: AssitantsComponent,
        canActivate: [AuthGard],
        data: { roles: [ROLE_LIST_ENUM.ADMIN]} 
      },
      { path: 'client',
        component: ClientComponent,
        canActivate: [AuthGard]
        data: { roles: [ROLE_LIST_ENUM.CLIENT]}
      }
    ]
    

    Finally, in the AuthGuard:

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
      
         const accessToken = localStorage.getItem(AuthGard.LOCAL_STORAGE_ACCESS_TOKEN)
         if(!accessToken){
             return this.router.createUrlTree(['/auth'])
         }
    
         return this._hasRole(route.data);
      }
    
    private _hasRole(data: GENERIC_KEY_VALUE_INTERFACE): boolean {
            const userAvailableRoleList = jwtDecode<yourInterface>(yourToken).roles;
            const hasRole = !!(data['roles'] as string[])?.find(e => userAvailableRoleList.find(list => list === e));
    
            return hasRole;
        }
    
    export interface GENERIC_KEY_VALUE_INTERFACE {
      [key: string]: any;
    }
    

    Basically route.data holds the roles array defined in the routing file. The JWT token store some information - the user's role too. So I used jwtDecode to decode the token and get the roles of the user. Then I checked if the user has the correct role in its list, to be able to navigate to the given route.