web-dev-qa-db-ja.com

ログイン状態に応じてユーザーをルーターにリダイレクトする

ユーザーがログインしていない場合、ログインページに自動的にルーティングしたいと思います。

app.module.ts

import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { DashBoardComponent} from './dashboard/dashboard.component';
import { NotFoundComponent } from './not-found/not-found.component';

const APPROUTES: Routes = [
  {path: 'home', component: AppComponent},
  {path: 'login', component: LoginComponent},
  {path: 'dashboard', component: DashboardComponent},
  {path: '**', component: NotFoundComponent}
];

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    DashboardComponent
    NotFoundComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    MaterialModule.forRoot(),
    RouterModule.forRoot(APPROUTES)
  ],
  providers: [],
  bootstrap: [AppComponent]
})

ユーザーがログインしていない場合はLoginComponentがロードされ、そうでない場合はDashboardComponentがロードされます。

30
Rafael Moura

優先度の低いものからお気に入りまで、あなたが尋ねたことを行う3つの方法を次に示します。

オプション1. AppComponentでユーザーを強制的にリダイレクトする

@Component({
  selector: 'app-root',
  template: `...`
})
export class AppComponent {
  constructor(authService: AuthService, router: Router) {
    if (authService.isLoggedIn()) {
      router.navigate(['dashboard']);
    }
  }
}

あまりよくない。 「ログインが必要」な情報は、それが属するルート宣言に保持する方が良いでしょう。

オプション2. CanActivateガードを使用します

ユーザーのログインが必要なすべてのルートにCanActivateガードを追加します。

const APPROUTES: Routes = [
  {path: 'home', component: AppComponent, canActivate:[LoginActivate]},
  {path: 'dashboard', component: DashBoardComponent, canActivate:[LoginActivate]},
  {path: 'login', component: LoginComponent},
  {path: '**', component: NotFoundComponent}
];

ガードはLoginActivateと呼ばれます。

それが機能するには、モジュールのprovidersにガードを追加する必要があります。

そして、それを実装する必要があります。この例では、ユーザーがログインしていない場合、ガードを使用してユーザーをリダイレクトします。

@Injectable()
export class LoginActivate implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean>|Promise<boolean>|boolean {
    if (!this.authService.isLoggedIn()) {
      this.router.navigate(['login']);
    }
    return true;
  }
}

これが意味をなさない場合は、ルートガードに関するドキュメントをご覧ください。 https://angular.io/docs/ts/latest/guide/router.html#guards

このオプションの方が優れていますが、それほど柔軟ではありません。ユーザーのアクセス許可など、「ログイン」以外の条件を確認する必要がある場合はどうなりますか?ロールの名前「admin」、「editor」などのパラメーターをガードに渡す必要がある場合はどうなりますか?

オプション3.ルートdataプロパティを使用します

私見の最良の解決策は、ルート宣言にいくつかのメタデータを追加して、「このルートではユーザーがログインする必要がある」ことを示すことです。

そのためにroute dataプロパティを使用できます。任意のデータを保持でき、この場合、requiresLoginまたはtrueのいずれかであるfalseフラグを含めることを選択しました(フラグが定義されていない場合は、falseがデフォルトになります) :

const APPROUTES: Routes = [
  {path: 'home', component: AppComponent, data:{requiresLogin: true}},
  {path: 'dashboard', component: DashBoardComponent, data:{requiresLogin: true}}
];

dataプロパティ自体は何もしません。しかし、これを使用して「ログインが必要」なロジックを実施できます。そのためには、もう一度CanActivateガードが必要です。

残念です、あなたは言います。次に、保護された各ルートに2つのものを追加する必要があります。メタデータとガード...

しかし:

  • CanActivateガードを最上位のルートにアタッチすると、そのすべての子ルートに対して実行されます[確認される]。そうすれば、ガードを1回使用するだけで済みます。もちろん、保護するルートがすべて親ルートの子である場合にのみ機能します(Rafael Mouraの例には当てはまりません)。
  • dataプロパティにより、あらゆる種類のパラメーターをガードに渡すことができます。特定のロールの名前またはチェックする権限、ユーザーがページにアクセスするために必要なポイントまたはクレジットの数など。

これらの発言を考慮して、ガードの名前をAccessGuardのようなより一般的なものに変更するのが最善です。

ガード内で行うことは実際に状況に依存するため、ガードがルートに接続されたdataを取得するコードのみを示します。

@Injectable()
export class AccessGuard implements CanActivate {
  canActivate(route: ActivatedRouteSnapshot): Observable<boolean>|Promise<boolean>|boolean {
    const requiresLogin = route.data.requiresLogin || false;
    if (requiresLogin) {
      // Check that the user is logged in...
    }
  }
}

上記のコードを実行するには、次のようなルートが必要です。

{
  path: 'home',
  component: AppComponent,
  data: { requiresLogin: true },
  canActivate: [ AccessGuard ]
}

NB。 AccessGuardをモジュールのprovidersに追加することを忘れないでください。

73
AngularChef

次のようなこともできます:

{
  path: 'home',
  component: getHomeComponent(),
  data: { requiresLogin: true },
  canActivate: [ AccessGuard ]
}

その後:

export function getHomeComponent(): Type<Component> {
  if (User.isLoggedIn) {
    return <Type<Component>>HomeComponent;
  }
  else{
    return <Type<Component>>LoginComponent;
  }
}
2