简体   繁体   中英

Angular2 routing canActivate and AuthGuard (JWT) with user role parameter

In this exaple project with JWT authentication we se how to allow only authenticated users to some route:

import { RouterConfig } from '@angular/router';
import { Home } from './home';
import { Login } from './login';
import { Signup } from './signup';
import { AuthGuard } from './common/auth.guard';

export const routes: RouterConfig = [
  { path: '',       component:  Login },
  { path: 'login',  component: Login },
  { path: 'signup', component: Signup },
  { path: 'home',   component: Home, canActivate: [AuthGuard] },
  { path: '**',     component: Login },
];

I would like make step further and also indicate what user role have 'access' to route - but I don't know how to pass argument to canActivate AuthGuard (src) . So I would like to achieve something like this (for instance I have two roles: Admin and Employee):

  { path: 'home',   component: Home, canActivate: [AuthGuard] },
  { path: 'users',   component: AdminUsers, canActivate: [AuthGuard('Admin')] },
  { path: 'users',   component: Employees, canActivate: [AuthGuard('Employee')] },

Where my AuthGuard could look something like this (where userRole(= Admin or Employee or null) is passed parameter to AuthGuard):

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(userRole) {
    if (!userRole || JWT.user().role == userRole) {
      return true;
    }

    this.router.navigate(['/login']);
    return false;
  }
}

where JWT.user.role is helper which read user role stored in JWT token. Is there a way to do something similar like above idea?

You can set the data parameter of the route with the role like this

 const appRoutes: Routes = [ { path: 'account/super-secure', component: SuperSecureComponent, canActivate: [RoleGuard], data: { roles: ['super-admin', 'admin'] } }]; 

and then have this in canActivate of RoleGuard :

 canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { let roles = route.data["roles"] as Array<string>; return (roles == null || roles.indexOf("the-logged-user-role") != -1); } 

I think this could be another way of doing it instead of creating guard for every role. I would actually take this rout since it requires less code and handles the problem very nicely.

The signature for CanActivate won't allow you to pass a userRole like you want to. https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/router/src/interfaces.ts#L54

It's probably best to do separate classes for each of your user role cases. That's the guidance in the official docs too: https://angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html

NOTE : applicable for angular-rc.4 <

@KamilKiełczewski, @NikolayRusev,

  1. added in route additional data with array of routes:

...
{
    path: "customers",
    component: CustomersCmp,
    data: { roles: ["admin"] }
},
...

and in CanActivate you can get path from first parameter, search the same path in route config and get your described roles from data:

public canActivate(route: ActivatedRouteSnapshot): boolean {
    let path = route._urlSegment.pathsWithParams[0].path;
    let roles;

    if (route._routeConfig.path == path) {
        roles = route._routeConfig.data.roles
    } else {
        roles = route._routeConfig.children.find(_route => _route.path == path).data.roles;
    }

    if (...) {
        return true;
    }

    return false;
}

Of course it would be better to avoid private properties, and you can, but I cannot remember how I exactly done it.

But for my porposes I redid it in different way. The huge disadvantage of this approach, I mean for role based guard, is that every user with different roles can see all of the routes if you render them in a component automatically not manually.

  1. you can extend router-outlet

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM