带有用户角色参数的 Angular2 路由 canActivate 和 AuthGuard (JWT)
Posted
技术标签:
【中文标题】带有用户角色参数的 Angular2 路由 canActivate 和 AuthGuard (JWT)【英文标题】:Angular2 routing canActivate and AuthGuard (JWT) with user role parameter 【发布时间】:2016-11-19 01:22:45 【问题描述】:在这个带有 JWT 身份验证的exaple project 中,我们了解如何只允许经过身份验证的用户访问某些路由:
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(= Admin or Employee or null) 将参数传递给 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 令牌中的用户角色的助手。有没有办法做类似上述想法的事情?
【问题讨论】:
我们不能将 AuthGuard 扩展为 AdminAuthGuard 和 UserAuthGuard 并在死记硬背的声明中将它们传递给 canActivate 钩子 我知道,这样 - 这是解决方法。但我想知道,确实存在类似于上述问题想法的其他方式。 我不这么认为,因为在路由声明期间,您只指定了警卫类。你可以通过多个类。 我是 Angular5 的新手,我正在努力解决同样的问题。如果您的问题得到解决,那么您可以分享您的代码吗? 【参考方案1】: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
【讨论】:
这个答案是正确的,在我提出问题的时候 - 这就是为什么绿色“检查”在这里的原因。但是对于新的角度版本,有更好的解决方案(阅读下面的答案)【参考方案2】:注意:适用于angular-rc.4
@KamilKiełczewski,@NikolayRusev,
在路由数组中添加了附加数据:
...
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
http://www.captaincodeman.com/2016/03/31/angular2-route-security/
https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492#.cxgoan9go
【讨论】:
很高兴听到来自 angular2 团队成员之一的评论。目前,似乎大多数人都在按照 Andrei Shostik 的方式进行操作,这似乎很老套。您需要在加载时阅读角色,然后通过您的路线并根据路线检查角色。如果故意限制无法访问 CanActivate 中的数据,我们不应该使用它。并且知道正确的方法会很好。如果它不是故意的,我们需要知道“正确”的解决方法。似乎也是相同的方法:***.com/a/39097563/145334 对于我之前的评论,似乎 github 上的这个问题是相关的:github.com/angular/angular/issues/9001 也针对这种情况提交了问题:github.com/angular/angular/issues/11708【参考方案3】:可以像这样设置路由的data
参数
const appRoutes: Routes = [
path: 'account/super-secure',
component: SuperSecureComponent,
canActivate: [RoleGuard],
data: roles: ['super-admin', 'admin']
];
然后在canActivate
的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);
我认为这可能是另一种方法,而不是为每个角色创建后卫。我实际上会采用这种方式,因为它需要更少的代码并且可以很好地处理问题。
【讨论】:
当我尝试使用您的解决方案时,我看到以下错误:Property 'data' does not exist on type 'ActivatedRouteSnapshot'.
我认为您的解决方案仅适用于旧版本的 angular2
@Kamil Kietczewski,该解决方案至少适用于 angular 2 (~2.0.1) 和新路由器 ~3.0.1。可能是您使用的是旧路由器。
我为 Angular 2.0.0-rc.3 测试了它 - 我在我的项目中使用这个版本 - 但我会尝试升级我的项目并测试你的解决方案......所以请耐心等待
如果你的用户可以有多个角色,你可以编辑这个来找出 route.roles 数组和 user.roles 数组的交集:user.roles.filter(r => route.roles.indexOf(r) !== -1).length > 0
这似乎是访问路由的方法,但是根据角色显示或隐藏组件怎么样?以上是关于带有用户角色参数的 Angular2 路由 canActivate 和 AuthGuard (JWT)的主要内容,如果未能解决你的问题,请参考以下文章