web-dev-qa-db-ja.com

Angular2ルーティングcanActivate and AuthGuard(JWT)with user role parameter

この 例のプロジェクト では、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) に渡す方法がわかりません。だから私はこのような何かを達成したいと思います(例えば、私は2つの役割を持っています:管理者と従業員):

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

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

ここで、JWT.user.roleは、JWTトークンに保存されているユーザーロールを読み取るヘルパーです。上記のアイデアのような何かをする方法はありますか?

41

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

6
cienki

このような役割を持つルートのdataパラメーターを設定できます

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

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

これは、すべての役割にガードを作成する代わりに、別の方法で行うことができると思います。必要なコードが少なく、問題を非常にうまく処理できるので、実際にこのルーティングを使用します。

82
Arman

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

もちろん、プライベートプロパティを避ける方が良いでしょうし、できますが、私がどうやってそれを行ったかを思い出せません。

しかし、私の目的のために、私は別の方法でそれをやり直しました。このアプローチの大きな欠点は、ロールベースのガードの場合、異なるロールを持つすべてのユーザーが、手動ではなくコンポーネントで自動的にレンダリングする場合、すべてのルートを見ることができるということです。

  1. router-outlet [.____を拡張できます。]
2
Andrei Shostik