javascript - canactivate - authguard roles
El enrutamiento Angular2 puede activar y AuthGuard(JWT) con un parámetro de rol de usuario (3)
En este proyecto de exaple con autenticación JWT, vemos cómo permitir solo a los usuarios autenticados alguna ruta:
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 },
];
Me gustaría dar un paso más y también indicar qué función de usuario tiene ''acceso'' a la ruta, pero no sé cómo pasar argumentos a canActivate AuthGuard (src) . Así que me gustaría lograr algo como esto (por ejemplo, tengo dos roles: administrador y empleado):
{ path: ''home'', component: Home, canActivate: [AuthGuard] },
{ path: ''users'', component: AdminUsers, canActivate: [AuthGuard(''Admin'')] },
{ path: ''users'', component: Employees, canActivate: [AuthGuard(''Employee'')] },
Donde mi AuthGuard podría verse algo así (donde userRole (= Admin o Employee o null) pasa el parámetro a 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;
}
}
donde JWT.user.role es helper, que lee el rol de usuario almacenado en el token JWT. ¿Hay alguna manera de hacer algo similar a la idea anterior?
La firma de CanActivate
no le permitirá pasar una userRole
como desee. https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/router/src/interfaces.ts#L54
Probablemente sea mejor hacer clases separadas para cada uno de los casos de roles de usuario. Esa es la orientación en los documentos oficiales también: https://angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html
Puede establecer el parámetro de data
de la ruta con el rol como este
const appRoutes: Routes = [
{
path: ''account/super-secure'',
component: SuperSecureComponent,
canActivate: [RoleGuard],
data: { roles: [''super-admin'', ''admin''] }
}];
y luego tener esto en canActivate
de 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);
}
Creo que esta podría ser otra forma de hacerlo en lugar de crear guardia para cada función. De hecho tomaría esta ruta ya que requiere menos código y maneja el problema muy bien.
NOTA : aplicable para angular-rc.4 <
@ KamilKiełczewski, @NikolayRusev,
Se agregaron datos adicionales en ruta con una matriz de rutas:
...
{
path: "customers",
component: CustomersCmp,
data: { roles: ["admin"] }
},
...
y en CanActivate puede obtener la path
desde el primer parámetro, buscar la misma ruta en la configuración de la ruta y obtener las funciones descritas de los datos:
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;
}
Por supuesto, sería mejor evitar las propiedades privadas, y puedes, pero no recuerdo cómo lo hice exactamente.
Pero para mis propósitos, lo rehice de otra manera. La gran desventaja de este enfoque, me refiero a la protección basada en roles, es que cada usuario con roles diferentes puede ver todas las rutas si las representa en un componente automáticamente y no manualmente.