Ionic4+firebase アカウント登録ページの実装とGuardの設定

#はじめに
[Ionic4+Firebase ゼロから10分でユーザ認証を実装する](https://qiita.com/se_fy/items/386418f123fc30c306e6)の続きです。
今回はアカウント登録ページを追加します。
また、前回はログインを実装しましたが、現状ではホームページに直接アクセスできてしまいます。
アカウントを登録し、登録したアカウントでログインしたときだけホームページに遷移するように実装していきます。

#アカウント登録ページを作る
1.アカウント登録ページのファイルを生成

```
$ ionic g page signup
```

2.アカウント登録ページの作成

```/src/app/signup/signup.page.html
<ion-header>
  <ion-toolbar>
    <ion-title>アカウント登録</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content padding>
  <form #f="ngForm" class="signupForm">
    <ion-item class="formItem">
      <ion-label position="floating">
        <ion-icon name="mail"></ion-icon>メールアドレス
      </ion-label>
      <ion-input
        required
        email
        [(ngModel)]="signup.email"
        type="email"
        name="signup.email"
      ></ion-input>
    </ion-item>

    <ion-item class="formItem">
        <ion-label position="floating">
          <ion-icon name="key" ></ion-icon>パスワード
        </ion-label>
        <ion-input
          required
          [(ngModel)]="signup.password"
          type="password"
          name="signup.password"
        ></ion-input>
    </ion-item>

    <ion-item class="formItem">
        <ion-label position="floating">
          <ion-icon name="person" ></ion-icon>名前
        </ion-label>
        <ion-input
          required
          [(ngModel)]="signup.name"
          type="text"
          name="signup.name"
        ></ion-input>
    </ion-item>

    <ion-button
      class="submitBtn"
      [disabled]="!f.form.valid"
      (click)="signUp()"
      size="large"
      expand="block"  
    >
      アカウント登録
    </ion-button>
  </form>

  <ion-button class="subLink" (click)="goBack()" fill="clear">
    ログインはこちら
  </ion-button>
</ion-content>

```

3.アカウント登録処理の実装

```/src/app/signup/signup.page.ts
import { Component, OnInit } from '@angular/core';
import { ToastController } from '@ionic/angular';
import { Router } from '@angular/router';

//Firebase
import { AngularFireAuth } from '@angular/fire/auth';

@Component({
  selector: 'app-signup',
  templateUrl: './signup.page.html',
  styleUrls: ['./signup.page.scss']
})
export class SignupPage implements OnInit {
  signup: {
    email: string;
    password: string;
    name: string;
  } = {
    email: '',
    password: '',
    name: '',
  };

  constructor(
    private router: Router,
    private toastCtrl: ToastController,
    private afAuth: AngularFireAuth
  ) {}
  
  ngOnInit() {}

  signUp() {
    this.afAuth.auth
      .createUserWithEmailAndPassword(this.signup.email, this.signup.password)
      //ユーザー登録が成功したらthenの中が実行される
      .then(created => {
        this.goBack();
    })
    .catch(async error => {
      const toast = await this.toastCtrl.create({
        message: error.toString(),
        duration: 3000
      });
      await toast.present();
    });
  }

  goBack(){
    this.router.navigate(['/login']);
  }
}
```

#ログインページからアカウント登録できるようにする
1.login.page.htmlに以下を追加する

```/src/app/login/login.page.html
<ion-button class="subLink" (click)="gotoSignup()" fill="clear">
    アカウント登録はこちらから
</ion-button>
```

2.login.page.tsに以下を追加する

```/src/app/login/login.page.ts
gotoSignup(){
    this.router.navigateByUrl('/signup');
  }
```

#動作確認
1.ログイン画面にアクセスしてアカウント登録し、そのアカウントでログインできます。
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410068/81b0e3d2-5813-fa0c-e51e-441564920910.gif)

2.Firebaseコンソールにアカウントが追加されていることが確認できます。
<img width="963" alt="スクリーンショット 2019-07-27 11.19.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410068/7b52ef71-4d16-1bf4-52f4-d1750d8b7ecc.png">




#ホームページに直接アクセスできないようにする
現状ではホームページにそのままアクセスできてしまいます。
http://localhost:8000/home
これではログインの意味がありません。
これをAngularのGuard機能を使って、ログインしていない状態でのホームページへの遷移を禁止します。

1.ガードを設定するための以下コマンドを実行

```
$ ionic g guard login
```

2.処理を実装

```src/app/login.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { AngularFireAuth } from '@angular/fire/auth';

@Injectable({
    providedIn: 'root'
})
export class LoginGuard implements CanActivate {
    constructor(
        private afAuth: AngularFireAuth,
        private router: Router
    ) {}

    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ): Observable<boolean> | Promise<boolean> | boolean {
        return this.afAuth.authState.pipe(
            // ログインの状態を取得
            take(1),
            map(user => {
                if (user !== null) {
                    // ログインしていた場合userにユーザーの情報が入る
                    return true;
                } else {
                    // ログインしていない場合は/loginに遷移
                    this.router.navigate(['/login']);
                    return false;
                }
            })
        );
    }
}
```

3.`app-routing.module.ts`を以下のように修正する

```src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
import { LoginGuard } from './login.guard'; //追記部分

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: './home/home.module#HomePageModule' },
  { path: 'login', loadChildren: './login/login.module#LoginPageModule', 
  canActivate: [LoginGuard]}, //追記部分
  { path: 'signup', loadChildren: './signup/signup.module#SignupPageModule' },
];

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

ホームページにアクセスしようとするとログインページに遷移することが確認できます。
http://localhost:8000/home

#参考
[初心者でも大丈夫!! IonicとFirebaseでゼロからはじめるアプリ開発](https://www.amazon.co.jp/dp/4844398709)
[Firebase - Ionic Framework 日本語ドキュメンテーション](https://ionicframework.com/jp/docs/native/firebase)
https://www.freakyjolly.com/ionic-4-create-simple-login-and-prevent-page-access-using-angular-guards/