web-dev-qa-db-ja.com

Angular2:グローバルガード(ユーザーは常にログインする必要があります)

認証されていないユーザーがまったくアクセスできないアプリケーションを構築しています。

LoggedInGuardを作成しましたが、ルーター構成内のeveryルートにcanActivate: [LoggedInGuard]を追加する必要があります(LoginComponentを除く)。

これを機能させるためのより良い方法はありますか?


私のファイル/モジュールのレイアウトは次のようになります。

app/
  AppModule
  AppRoutingModule
  AppComponent

  authentication/
    AuthenticationModule
    AuthenticationRoutingModule
    LoginComponent

  contacts/
    ContactsModule
    ContactsRoutingModule
    ContactListComponent

  users/
    UsersModule
    UsersRoutingModule
    UserEditComponent

  ...

たぶん、2つの別々のルーティングスペース(1つはログイン用、もう1つはアプリの残りの部分用)を作成し、アプリの残りの部分にのみガードを適用することが可能です。 )一部?


簡単な解決策があるといいのですが。

前もって感謝します!

9
Benjamin M

私はもっ​​と論理的な方法でそれをしていると思います。意見だと思います。アプリケーションをsecured pagespublic pagesで区切ります。セットごとにテンプレートを使用しています。したがって、public componentsecure componentは、guardsecure templateに配置します。

保護が必要なフルルートに[Guard]を追加していることを確認してください。

したがって、ルートを確保するときに、親をapp.routing.tsに追加します

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', },
    { path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
    { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];



export const routing = RouterModule.forRoot(APP_ROUTES);

この行に注意してください。

 { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }

だから私は2つのレイアウトを作成します

/ public /すべてのパブリックコンポーネント

/ public/public.routes.ts

/ secure /すべてのセキュアコンポーネント

/ secure/secure.routes.ts

安全なルート

これらのルートはテンプレートの親によって処理されるため、Guardは必要ないことに注意してください。

export const SECURE_ROUTES: Routes = [
    { path: '', redirectTo: 'overview', pathMatch: 'full' },
    { path: 'items', component: ItemsComponent },
    { path: 'overview', component: OverviewComponent },
    { path: 'profile', component: ProfileComponent },
];

app.routing.tsのメインルート

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full', },
    { path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
    { path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];

export const routing = RouterModule.forRoot(APP_ROUTES);

そして、ディレクトリ/ layoutsに、次のようなレイアウトを作成します。

/ layouts/secure.component.ts

/ layouts/secure.component.html

/ layouts/public.component.ts

/ layouts/public.component.html

すべてがレイアウトpublicまたはsecureを介してルーティングされ、[Guard]は安全です。

次に、ローカルストレージ内のトークンを使用して認証を処理します。

@Injectable()
export class Guard implements CanActivate {

    constructor(protected router: Router, protected auth: Auth ) {}

     canActivate() {
        if (localStorage.getItem('access_token')) {
            // logged in so return true
            return true;
        }
        // not logged in so redirect to login page
        this.router.navigate(['/home']);
        return false;
    }
}

このようにアプリを設定したら、セキュリティで保護する必要のあるすべてのルートをセキュアディレクトリに配置し、パブリックルートをパブリックに配置します。次に、それぞれのディレクトリにあるpublic.routes.tsファイルまたはsecure.routes.tsファイルにルートを作成します。

7
wuno

ガードをルーターイベントリスナーに移動することで、複数のモジュールにまたがるグローバルガードのセットを提供することができました。

すべてのリクエストに対してイベントリスナーを起動させるために、AppComponentに挿入しました。

以下の両方の例で、個々のルートにカスタムガードを追加することができ、それらは引き続き機能することに注意してください。

警備員なし

ガードの使用を削除し、代わりにイベントリスナーにロジックを直接実装できます。

import { Component, OnInit } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';

// I use a service to keep track of the authentication ticket.
// Replace this with whatever mechanism you use.
import { AuthenticationService }  from './_services/index';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  constructor(
      private router: Router,
      private authService: AuthenticationService
  ) {}

  ngOnInit() {
    this.router.events
    .filter(event => event instanceof RoutesRecognized)
    .subscribe((event: RoutesRecognized) => {
      const url = event.urlAfterRedirects;

      // Public URLs don't need any kind of authorization.
      if (url === '/public' || url.startsWith('/public/') || url.startsWith('/public?')) {
        return;
      }

      // Everything else must be authenticated.
      if (!this.authService.isAuthenticated()) {
        // Allow for the login page to redirect back to the originally
        // requested page.
        this.router.navigate(['/public/login'], { queryParams: { returnUrl: state.url } });
      }
    });
  }
}

/publicのサブページに渡されたリクエストは関係なく通過しますが、他のリクエストには認証が必要です。そうでない場合、/public/loginにリダイレクトされます。

リダイレクトページが保護領域にないように注意してください。そうしないと、ルーターが無限ループに入ります。

警備員付き

以下の実装は、既存のガードを再利用する方法を示しています。これは、それらを保持する必要がある場合、またはコードをよりクリーンにする場合のみです。

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, RoutesRecognized, CanActivate } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

// Reused guards.
import { AdminGuard, AuthGuard } from './_guards/index';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  constructor(
      private route: ActivatedRoute,
      private router: Router,
      private adminGuard: AdminGuard,
      private authGuard: AuthGuard
  ) {}

  ngOnInit() {
    this.router.events
    .filter(event => event instanceof RoutesRecognized)
    .subscribe((event: RoutesRecognized) => {
      // Public pages don't require authentication.
      if (this.isSubPage(event, '/public')) {
        return;
      }

      // All other requests MUST be done through an
      // authenticated connection.  The guard performs
      // the redirection for us.
      if (!this.callCanActivate(event, this.authGuard)) {
        return;
      }

      // Administration pages require additional restrictions.
      // The guard performs the redirection for us.
      if (this.isSubPage(event, '/admin')) {
        if (!this.callCanActivate(event, this.adminGuard)) {
          return;
        }
      }
    });
  }

  callCanActivate(event: RoutesRecognized, guard: CanActivate) {
    return guard.canActivate(this.route.snapshot, event.state);
  }

  isSubPage(event: RoutesRecognized, parent: string) {
    const url = event.urlAfterRedirects;
    return (url === parent
        || url.startsWith(parent + '/')
        || url.startsWith(parent + '?'));
  }
}

この例は上記の例と同じですが、/admin領域の保護が追加されており、ユーザーが管理者権限も持っていることが保証されます。

4
Groboclown