2016-07-15 162 views
35

在这种exaple project智威汤逊验证我们自身如何只允许被授权的用户的一些路线:Angular2路由canActivate和AuthGuard(JWT)

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 }, 
]; 

我想作一步,也表明了什么用户角色有'访问'路由 - 但我不知道如何将参数传递给canActivate AuthGuard (src)。所以我想实现这样的事情(比如我有两个角色:管理员和员工):

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

凡我AuthGuard可能看起来像这样(其中的UserRole(=管理员或雇员,或空)传递参数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; 
    } 
} 

其中JWT.user.role是帮助其读取存储在JWT令牌用户角色。有没有办法做类似上面的想法?

+1

我们不能将AuthGuard扩展为AdminAuthGuard和UserAuthGuard,并通过canActivate钩子在死记硬背宣告 –

+0

这样做 - 这是解决方法。但我想知道,确实存在类似于上述问题的其他方式。 –

+1

我不这么认为,因为在路线声明中你只指定了守卫类。你可以传递多个类。 –

回答

4

CanActivate的签名将不会允许您通过userRole,如您所愿。 https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/router/src/interfaces.ts#L54

最好为每个用户角色案例分别设置类。这是在官方文档也指导:https://angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html

+1

这一点不是传递userRole到:canActivate(userRole),而是将userRole传递给AuthGuard(可能在构造函数或其他东西?):canActivate:[AuthGuard('Admin')] –

+0

您是否设法找到解决方案? –

+3

这个答案是正确的,在我问问题的时候 - 这就是为什么绿色'检查'在这里的原因。但对于新的角度版本有更好的解决方案(阅读下面的答案) –

1

注意:适用于角rc.4 <

@KamilKiełczewski,@NikolayRusev,

  1. 加入航线附加数据有一系列路线:

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

和CanActivate你可以从第一个参数得到path,搜索在航线配置相同的路径和从数据得到你所描述的角色:

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; 
} 

当然会更好,以避免私人财产,并可以,但我不记得我是如何做到的。

但是对于我的手表,我用不同的方式重新配置它。这种方法的巨大缺点,我的意思是基于角色的防范,就是每个拥有不同角色的用户都可以看到所有的路由,如果你不自动地在组件中渲染它们。

  • 可以延长router-outlet
  • +0

    很高兴听到来自angular2团队成员之一的评论。现在看来大多数人都这样做,这是你的方式安德烈Shostik,这似乎hacky。您需要阅读载入的角色,然后通过您的路线并根据路线检查角色。如果在CanActivate中无法访问数据的限制是故意的,我们不应该使用它。并且知道正确的方式会很好。如果它不是故意的,我们需要知道“正确”的解决方法。似乎同样的方法,以及:http://stackoverflow.com/a/39097563/145334 –

    +0

    在我以前的评论,似乎这个问题在github是相关的:https://github.com/angular/angular/issues/9001 –

    +0

    这个问题也适用于这种情况:https://github.com/angular/angular/issues/11708 –

    66

    您可以设置路由的data参数,像这样的角色

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

    ,然后让这canActivateRoleGuard的:

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

    我认为这可能是做这件事,而不是为每个角色创建后卫的另一种方式。因为它需要较少的代码并且很好地处理了这个问题,所以我实际上会采用这种方法。

    +1

    当我尝试使用你的解决方案时,我看到以下错误: '属性'数据'不存在类型'ActivatedRouteSnapshot ''。' 我认为你的解决方案只适用于老版本的angular2 –

    +0

    我已经使用angular 2(2.0.2)进行了测试,并且它适用于我... – Zasuk

    +0

    @Kamil Kietczewski,解决方案适用于angular 2(〜2.0 .1)至少和新的路由器〜3.0.1。这可能是您正在使用旧的路由器。 – Arman