角度ダーツルータ-ルートフックを使用してルートを保護する方法


この記事では、どのようにルートを保護する方法を学びますRouterHook and CanActivate ガード.私はあなたが既にあなたの角度ダーツアプリケーションと基本的なルーティングを設定すると仮定しますTour of Heroes 角度チームからのチュートリアル

オーササービス
起動する前に、ユーザがログインしているかどうかを知る方法が必要です.認証を実装する方法をカバーしませんが、次のインターフェイスに似たものが必要です.
abstract class AuthService {
  bool get isLogged;

  // request API or check storage then set isLogged boolean
  Future<void> checkIsLogged();

  ... login, register
}

始めましょう
以下の路線がある./login
  • ユーザーがログオンしていない場合にのみアクセス可能である必要があります
  • リダイレクトするdashboard 既にログインしている場合
  • /dashboard
  • ユーザーがアクセスするためにログインする必要があります
  • リダイレクトするlogin を返します.
  • ルートを保護する最速の方法は、実装することですCanActivate 各ルートのクラス.
    import 'package:angular_router/angular_router.dart';
    
    class DashboardPageComponent implements CanActivate {
      final AuthService authService;
    
      DashboardPageComponent(this.authService);
    
      @override
      Future<bool> canActivate(RouterState current, RouterState next) {
        // don't activate the route if not logged
        return authService.isLogged;
      }
    }
    
    しかし、このメソッドは、多くのboilerplateコードを生成し、一度アプリケーションが大きくなっている維持するのは難しいです.保護する各コンポーネントルートでそれを実装する必要があります.
    代わりに、我々はisLogged すべてのルートをチェックし、我々はどのルートが保護され、どちらがされていない設定する方法が必要です.そのためには、RouterHook それはcanActivate 方法と我々のルート定義にカスタム設定を使用します.

    ルート定義
    import 'package:angular_router/angular_router.dart';
    
    import 'login.template.dart' as login_template;
    import 'dashboard.template.dart' as dashboard_template;
    
    class RouteConfig {
      final bool protected;
      final bool redirectIfLoggedIn;
    
      RouteConfig({
        this.protected = false,
        this.redirectIfLoggedIn = false,
      });
    }
    
    final routes = [
      RouteDefinition(
        path: 'login',
        component: login_template.LoginPageComponentNgFactory,
        additionalData: RouteConfig(redirectIfLoggedIn: true),
      ),
      RouteDefinition(
        path: 'dashboard',
        component: dashboard_template.DashboardPageComponentNgFactory,
        additionalData: RouteConfig(protected: true),
      ),
    ];
    

    ルーターフック

    A class should extend this class and be injected along with the router to hook into route navigation. Documentations


    基本的に、これはルータがすべてのルート・コンポーネントでそれを実行する代わりにルートに操縦しようとしているたびにルータ・ガードを実行する方法です.(アクティブになって、アクティブにします.
    import 'package:angular/angular.dart';
    import 'package:angular_router/angular_router.dart';
    
    class AppRouterHook extends RouterHook {
      final AuthService _authService;
      final Injector _injector;
    
      AppRouterHook(this._authService, this._injector);
    
      // Lazily inject `Router` to avoid cyclic dependency.
      Router _router;
      Router get router => _router ??= _injector.provideType(Router);
    
      @override
      Future<bool> canActivate(
        Object componentInstance,
        RouterState oldState,
        RouterState newState,
      ) async {
        // TODO: check user access
        return true;
      }
    }
    
    デフォルトではcanActivate メソッドは、すべてのルートでユーザーを入力させます.

    なぜ使用_injector.provideType(Router) ?
    ルータは我々に注入できないRouterHook , フックが角で注入されるのでRouter そして、循環的な依存関係を引き起こします.
    次に、現在のRouteConfig とユーザーアクセスを確認します.
    final config = newState.routePath.additionalData;
    if (config is RouteConfig) {
      if (config.protected && !_authService.isLogged) {
        // redirect to login if not logged
        router.navigate(
          'login',
          NavigationParams(replace: true),
        );
        return false;
      }
    
      if (config.redirectIfLoggedIn && _authService.isLogged) {
        // redirect to dashboard if logged in
        router.navigate(
          'dashboard',
          NavigationParams(replace: true),
        );
        return false;
      }
    }
    

    初期化サービス
    ルータを初期化する前にユーザ状態を取得しなければならない.
    import 'package:angular/angular.dart';
    import 'package:angular_router/angular_router.dart';
    
    @Component(
      selector: 'my-app',
      styleUrls: ['app_component.css'],
      template: '<router-outlet *ngIf="isReady" [routes]="routes"></router-outlet>',
      directives: [
        routerDirectives,
        NgIf,
      ],
    )
    class AppComponent {
      final AuthService authService;
    
      bool isReady = false;
    
      AppComponent(this.authService) {
        authService.checkIsLogged().then((_) {
          isReady = true;
        });
      }
    }
    
    最後に、それをRouter とVoila!
    @GenerateInjector([
      ClassProvider(AuthService, useClass: AuthServiceImpl),
      ClassProvider(RouterHook, useClass: AppRouterHook),
      routerProvidersHash,
    ])
    final injectorFactory = template.injectorFactory$Injector;
    

    更なる
    カスタマイズできますRouteConfig 独自のルールに従って、ユーザーロールに応じてルートを保護するように.
    RouteConfig(allowedRoles: [Role.admin, Role.editor]);
    
    または別のパスにリダイレクトします.
    RouteConfig(redirectIfNotLogged: 'home');