[SwiftUI]Firebase Authenticationで認証機能を実装する方法[SPM]

※最新の記事は社用のテックブログに記載しましたので最新の情報は以下を参考にしていただければと思います。
https://tech.nri-net.com/entry/firebase_swift_async_await

## 実装する機能
今回はFirebaseを使用して認証機能を実装していく方法をご紹介します。
FirebaseはGoogleが提供するmobile Backend as a ServiceでmBaaS（エムバース）と呼ばれており、データの管理や認証周りを簡単に実装する事ができます。
今回はFirebaseを利用して、アプリへの認証記録やアカウント管理を端末側では行わず、Firebase側に任せた実装を行なっていきます。

https://firebase.google.com/?hl=ja

## 環境
・ macOS: Monterey
・ Xcode: 13.1
・ SDK Version: iOS 8.10.0

## 内容
・Firebaseへの登録
・FirebaseをSwift Package Managerでインストール方法
・Firebase Authenticationで認証機能を設定
・メールアドレスとパスワードによる実装
　・Sign Inの実装
　・Sign Upの実装
　・Sign Outの実装
　・パスワードのリセット(変更方法)
以上です。
#### 認証機能の呼び方について
認証機能の呼び方につきましては
[ログイン] - [ログアウト]
[サインイン] - [サインアウト]
という言葉が用いられていますが、どちらも意味に違いはないそうです。今回は昨今の認証機能として"サインイン"を用いるケースが多いようなので[サインイン] - [サインアウト]で統一いたします。
(余談ですがWindowsも7まではログオン、ログオフという記入があったようですが現在(Win10)はサインイン、サインアウトとなっているそうです)
またアカウントを作る作業を[サイン アップ]とさせていただきます。

## 全体像
下記図のようにメールアドレスとパスワードを入力するとFirebase側に登録されいればサインインを行い、されていなければエラーを返します。
登録されていなければサインアップを行います。サインイン、サインアップのいずれかを行うとサインインの状態になり、サインアウトすることができます。
またパスワードを忘れたり、任意に変更したりすることもできます。これらを以下の図のようなイメージで作っていきたいと思います。(サインアップも同様)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/34217edc-a221-b356-029f-b37a8e606716.jpeg" width=60%>

## Firebaseへの登録
まずFirebaseを利用する準備を行います。Firebaseへの登録は5分もあればできると思います。
(Googleアカウントは必須になりますので持っていない方は作成してください)
登録は[コチラ](https://firebase.google.com/)から行えます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/d0d56fb6-b345-4458-09c2-f40a5d886f22.jpeg" width=60%>
使ってみるを選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/e82513dd-05f6-eaf0-9a33-d4b76f1d2fe4.jpeg" width=60%>
プロジェクトを追加を選択（既にプロジェクトがあるとここに表示される）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/aa475a4e-7465-9d15-8cdc-be358d0f06f8.jpeg" width=60%>
プロジェクトの作成途中にアナリティクスの有効の有無を聞いてきますが、無料でかつ強力なアナリティクスを使用できますので有効にする事をおすすめします。

後は手順通りに進めていけば問題ないです。途中GoogleService-Info.plistをダウンロードする画面が出てきますが、後で使用しますので分かる場所に保存しておく事をおすすめします。

## FirebaseをSwift Package Managerでインストール方法
projectより追加していきます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/e8435e29-6b36-54ab-b1c4-702332a1d12c.jpeg" width=60%>
赤枠部分を選択して追加していきます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/6eec5190-66cd-f33c-418d-b743eb24d909.jpeg" width=60%>
All Sourcesより赤枠の部分にgithub.com/firebase/firebase-ios-sdk.gitを入力してライブラリをインストールしていきます。
公式ドキュメントは[コチラ](https://firebase.google.com/docs/auth?hl=ja)

## Firebase Authenticationで認証機能を設定
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/9011f7eb-6197-50ea-2da9-5dddd46bff7e.jpeg" width=60%>
Firebaseで作成したプロジェクトを選択し
Authentication→Sign-method→新しいプロバイダを追加→メール/パスワード
を選択して追加することで、Firebase側でメールアドレスとパスワードで認証する機能を追加することができます。
下準備はここまでです。
## メールアドレスとパスワードによる実装
### AppDelegateの追加
最初にAppDelegateを追加していきます。(Xcode12以降プロジェクト開始時にSwiftUIを選択するとAppDelegateが初期で無いので追加しないといけません。)
アプリ名App.swiftファイルにimport FirebaseとAppDelegateクラスを以下のように追加します。

```swift
import Firebase

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions
                     launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        return true
    }
}
```
続いて同じファイル内にあるstructに@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegateを追加します。

```swift
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
```
AppDelegateの追加は以上です。

### GoogleService-Info.plistの追加

Firebaseでプロジェクトを作成する際GoogleService-Info.plistのダウンロードをしていると思いますのでファイルにドラッグ&ドロップで追加していきます。
![スクリーンショット 2022-01-09 15.49.24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/7e0ba629-c517-bf78-a004-8e760152848f.jpeg)

### SignInの実装

```swift
 Auth.auth().signIn(withEmail: email, password: password) { user, error in
    if error == nil {
        //サインイン成功
    } else {
        if let errorCode = AuthErrorCode(rawValue: error!._code) {
            switch errorCode {
            case .invalidEmail:
                //メールアドレスの形式によるエラー
            case .weakPassword:
                //パスワードが脆弱(6文字以下)
            case .wrongPassword:
                //パスワードが間違っている
            case .userNotFound:
                //ユーザー情報が見つからない(未登録)
            case .networkError:
                //通信エラー
            default:
              　 //その他エラー
            }
        }
    }
}
```
caseの後のエラーは補完でも沢山出てきますが必要なものだけ設定します。
### SignUpの実装

```swift
Auth.auth().createUser(withEmail: email, password: password) { result, error in
    if error == nil {
        //サインアップ成功
    } else {
        if let errorCode = AuthErrorCode(rawValue: error!._code) {
            switch errorCode {
            case .invalidEmail:
                //メールアドレスの形式によるエラー
            case .weakPassword:
                //パスワードが脆弱(6文字以下)
            case .emailAlreadyInUse:
                //メールアドレスが既に登録されている
            case .networkError:
                //通信エラー
            default:
                //その他エラー
            }
        }
    }
}
```
こちらもサインイン同様、必要なエラーハンドリングだけ設定します。

※サインインやサインアップのエラー処理については公式に詳細が掲載されていますので(こちら)[https://firebase.google.cn/docs/auth/ios/errors?hl=en&skip_cache=true%22]からどうぞ。
### SignOutの実装
サインアウトのメソッドにはthrowsが付いているので(エラーを投げる可能性のあるメソッド)do,try,catchを使用して以下のようにします。
![スクリーンショット 2022-01-06 13.06.25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517666/ed95ecc9-514b-f61d-bfb4-c694caf39988.jpeg)

```swift
do {
try Auth.auth().signOut()
    //サインアウトした時の処理
} catch {
    //エラー時の処理
}
```

## パスワードのリセット
以下のメソッドが成功すると入力したメールアドレスにFirebase AuthenticationのTemplates内にあるパスワードの再設定で設定した内容の文章が送られ、本文にあるリンクよりパスワードがリセットできるようになっている。


```swift
Auth.auth().sendPasswordReset(withEmail: email) { error in
    if error == nil {
        //成功した時の処理
    } else {
        if let errorCode = AuthErrorCode(rawValue: error!._code) {
            switch errorCode {
            case .userNotFound:
                //ユーザー情報が見つからない(未登録)
            case .invalidEmail:
                //メールアドレスの形式によるエラー
            default:
                //その他エラー
            }
        }
    }
}
```

## 最後に
これでFirebase Authenticationを利用して
　・Sign Inの実装
　・Sign Upの実装
　・Sign Outの実装
　・パスワードのリセット
ができます。誰かの役に立てば幸いです^^