Angular+Cognitoのユーザー認証にGuardを使う

# はじめに

以前、[Angular+Cognitoのユーザー認証付きSPAのサンプル]()という記事を書きましたが、このときは各コンポーネントでCognito認証済かどうかのチェックをのチェックを行っていましたが、AngluarにはGuardというルーティングを行うタイミングで、ルーティングの拒否、許可の分岐を行える仕組みがあります。
今回は、前回作成したサンプルをGuardを使った形に書き換えていきたいと思います。

# 手順

## guardの作成

angluar-cliにはguardを作成するgenerateコマンドも要されているので、簡単にひな形を作成することが出来ました。

```bash
$ ng g guard guard/auth
```
```ts:auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}
```

また、サービスを追加するときと同様にapp.module.tsにインポートし、`@NgModule`の`providers`に追加しておきます。

## guardの修正

前回の記事でcognito.service.tsに実装した`isAuthenticated ()`メソッドを使ってguard内で認証済み判定を行います。
angluar-cliで作成されたguardを見て分かる通り、canActivateはObservable、Promiseそれぞれのbooleanまたはbooleanを戻り値に取ることが出来ます。

```ts:auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { CognitoService } from './../service/cognito.service';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(
    private cognitoService: CognitoService,
    private router: Router
  ) {

  }
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Promise<boolean> {
      return this.cognitoService.isAuthenticated()
      .then(data => {
        return Promise.resolve(true);
      }).catch(err => {
        this.router.navigate(['/login']);
        return Promise.resolve(false);
      });
    }
}
```

上記では、CognitoServiceとRouterをインポートしています。
Routerをインポートするのは、認証済み出なかった場合に、loginページにリダイレクトするためです。

## Routerの設定
app-routing.module.tsを修正して、RouterでGuardを使用するように設定します。
認証が必要な、routes内の`upload `、`upload `オブジェクトにcanActivateパラメータを追加して先ほど作成したGuardを指定します。

```ts:app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SignupComponent } from './public/signup/signup.component';
import { LoginComponent } from './public/login/login.component';
import { UploadComponent } from './secure/upload/upload.component';
import { FilesComponent } from './pages/files/files.component';
import { AuthGuard } from './guard/auth.guard';

const routes: Routes = [
  {
    path: 'signup',
    component: SignupComponent,
  },
  {
    path: 'login',
    component: LoginComponent,
  },
  {
    path: 'upload',
    component: UploadComponent,
    canActivate: [AuthGuard]
  },
  {
    path: 'files',
    component: FilesComponent,
    canActivate: [AuthGuard]
  },
  {
    path: '',
    redirectTo: '/upload',
    pathMatch: 'full'
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```

## コンポーネントの修正

上記までの手順でguardの設定が済んだので、各コンポーネントのコンストラクタ内で行っている認証チェックのロジックを削除してしまいます。
`files.component.ts`、`upload.component.ts`それぞれの以下の箇所を削除します。

```diff:files.component.ts
-    this.cognito.isAuthenticated()
-    .then(res => console.log(res))
-    .catch((err) => {
-      return console.log(err) || this.router.navigate(['/login']);
-    });
```



手順としては以上です。
開発サーバーを立ち上げて、それぞれのページにアクセスすると正しくルーティングされているのが確認できるかと思います。


# 今回のサンプルコード

https://github.com/daikiojm/angular-cognito-s3-file-uploader/tree/feature/guard


# 参考

angular.io
https://angular.io/guide/router

Auth0 + AngluarのGuardを使った例ですが、大変参考になりました🙏
https://qiita.com/ovrmrw/items/f7003a5df4aa58cb4857