Javascript 带有用户角色参数的 Angular2 路由 canActivate 和 AuthGuard (JWT)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38402776/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 21:26:18  来源:igfitidea点击:

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

javascriptauthenticationangularrolesangular2-routing

提问by Kamil Kie?czewski

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

在这个带有 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 },
];

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):

我想更进一步,并指出哪些用户角色可以“访问”路由 - 但我不知道如何将参数传递给 canActivate AuthGuard (src)。所以我想实现这样的目标(例如我有两个角色:管理员和员工):

  { 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):

我的 AuthGuard 看起来像这样(其中 userRole(= Admin 或 Employee 或 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;
  }
}

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?

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

采纳答案by cienki

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

的签名CanActivate不允许你传递userRole你想要的。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

最好为每个用户角色案例做单独的类。这也是官方文档中的指导:https: //angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html

回答by Arman

You can set the dataparameter of the route with the role like this

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

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

and then have this in canActivateof RoleGuard:

再有这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);
}

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.

我认为这可能是另一种方式,而不是为每个角色创建警卫。我实际上会采取这种方式,因为它需要更少的代码并且可以很好地处理问题。

回答by Andrei Shostik

NOTE: applicable for angular-rc.4 <

注意:适用于angular-rc.4 <

@KamilKie?czewski, @NikolayRusev,

@KamilKie?czewski、@NikolayRusev、

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

  1. 在路由中添加了带有路由数组的附加数据:

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

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

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

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
  1. 你可以延长 router-outlet