Firebase Authによるメールアドレス＆パスワード認証（存在確認付き）

# ざっくり趣旨
- Firebase Authを使ってメールアドレスとパスワードによるユーザー登録を行います。
- そのメールアドレスが存在しているかチェックする機能も実装します。
- 公式ドキュメント以外の参考文献が意外と無かったので書くことにしました。
- iOS中心で書いてますがAndroidも同様にできるはず。

# 全体の流れ
1. Anonymous Authenticationによる匿名認証
2. メールアドレスとパスワードによる認証
3. 　1.で取得したuidを2.でもってメール認証ユーザーに昇格させる
4. 存在確認メール送信
5. メール内のリンクをタップ
6. 　5.で表示されたWebでもって存在確認が完了
7. アプリにURLスキームで戻りログイン完了

# 事前準備
公式ドキュメントを読みながら進めていくと後から必要なものが多数出てきて、それが原因で躓いたのでまとめ

- bundle ID（そもそもこれがないとFirebase使えない）
- iTunesConnectでアプリを新規登録しておく（AppStoreID, prefixが必要）
- FirebaseのDynamic Link設定（後述します）

## Firebase Dynamic Link設定
1. ディープリンクのURLとダイナミックリンク名を設定。
　メール認証で使う場合あまり重要でないっぽいので適当に（自身のテストサーバーのURLなどを）入れます。

<img width="400" alt="スクリーンショット 2017-11-16 14.37.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/214400/b31a3676-db41-2bda-9970-4cda35646e64.png">

２. iOS用のリンク動作の定義。
　ここもメール認証ではあまり影響なかったような。

<img width="350" alt="スクリーンショット 2017-11-16 14.37.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/214400/aced1e8f-7b04-b061-1b53-70c7f7bd77a5.png">

ただAppStoreID, prefixが無いとここから先に進めないので予め登録しておきます。めんどくさ。

<img width="350" alt="スクリーンショット 2017-11-16 14.37.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/214400/b001a643-2fe2-f391-f3dc-4e052940bc23.png">

ここもメール認証の場合はあまり影響せず。

# 実装
ここまできてようやく実装です。基本的なところは省略。

## 匿名認証

```objc:fuga.m
- (void)signInAnonymously:(void (^)(NSError *error))block
{    
    [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
        if (error) {
            if(block) block(error);
        } else {
            NSLog(@"uid = %@", [FIRAuth auth].currentUser.uid);
            if(block) block(nil);
        }
    }];
}
```
## メールアドレスとパスワードによる認証と存在確認メール送信
なお[[FIRAuth auth] useAppLanguage]は言語コードがどうにもうまく切り替わらず、言語別に設定されたメールが飛びませんでした。
actionCodeSettings.URLにURLスキームをセットします。info.plistの設定が必要なので設定しておきます。

```objc:fuga２.m
- (void)linkAnonymousWithEmailPwd:(void (^)(NSError *error))block
{
    FIRAuthCredential *credential = [FIREmailAuthProvider credentialWithEmail:_tf_email.text password:_tf_pass.text];
    [[FIRAuth auth].currentUser linkWithCredential:credential completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
        // ...
        if (error) {
            if(block) block(error);
        } else {
            [FIRAuth auth].languageCode = @"ja";
            FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init];
            actionCodeSettings.handleCodeInApp = YES;
            actionCodeSettings.URL = [NSURL URLWithString:@"hogefugapiyo://www.example.com/aaaaa/ccc.html"];
            [actionCodeSettings setIOSBundleID:@"com.piyo.fuga"];
            [user sendEmailVerificationWithActionCodeSettings:actionCodeSettings completion:^(NSError *_Nullable error) {
                if (error) {
                    if(block) block(error);
                } else {
                    if(block) block(nil);
                }
            }];
        }
    }];
}
```

## メール受信
こんなメールが届きます。

<img width="300" alt="IMG_0106.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214400/9c00e735-23fb-1d60-a3e1-94d6150417ed.png">

クリックするとブラウザに飛ばされて

<img width="300" alt="IMG_0107.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214400/d70f96bf-f62f-dac1-38bf-536903a914e2.png">

OPENを押すとメール認証

<img width="300" alt="IMG_0108.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214400/85b61c4a-fb6b-f1b6-62c8-ac5260ca436c.png">

CONTINUEを押すとactionCodeSettingsでセットしたURLスキームが発動します

<img width="300" alt="IMG_0109.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214400/ff9ea502-4214-edb6-f7f8-fd849b24f751.png">

で、アプリに戻って然るべき処理をして完了です。

## メール存在確認が済んでいるかチェック
ログインしてユーザーステータスを取得しないと分からないので、ログインします。
※存在確認が済んでいなくてもログインはできます。

```objc:fuga２.m
- (void)loginWithEmailPwd:(void (^)(NSError *error))block
{
    [[FIRAuth auth] signInWithEmail:_tf_email.text password:_tf_pass.text completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
        if (error) {
            if(block) block(error);
        } else {
            if(user.isEmailVerified != YES) {
                //not verified
                NSDictionary *info = @{@"NSLocalizedDescriptionKey": @"Email is not verified"};
                if(block) block([NSError errorWithDomain:@"com.example.app" code:-1 userInfo:info]);
            }else{
                if(block) block(nil);
            }
        }
    }];
}
```