Roba Memo - 素人のUnity覚書と奮闘記

素人のUnity覚書と奮闘記

Unity(C#)+FirebaseをWebGLで使いたい②:ログイン編

おさらい

前の記事の続きです。
Unity(C#)+FirebaseをWebGLで使いたい①:環境整備編 - Roba Memo - 素人のUnity覚書と奮闘記

やりたいこと

FirebaseのAuthenticationのメールリンクを使ってログインしたい。

メールリンクにすると、メールアドレスを登録するだけでログインできる。
公式によれば、ログイン状態はブラウザを閉じても保たれるらしい。(この設定を変更する事も可能)

とりあえず、ログインはjavascriptのみで行おうと思う。
ログイン後にWebGLを表示して、データベースとのやり取りをやっていくので、それは次項〜にて記述。

1:コンソールの設定

ログイン方法を設定

コンソールにログインして、Authentication > ログイン方法 > メール/パスワードにカーソルを合わせると鉛筆アイコンが右側に表示されるので、クリックする。
f:id:nico-taniku:20190712133835p:plain:w600
両方を「有効」にして「保存」
f:id:nico-taniku:20190712134041p:plain:w600

サポートメールを設定

確認メールに記載されるからだと思うが、これを設定しないといけないようなので、設定しておく。
後から変更可能。
f:id:nico-taniku:20190714061839p:plain

確認メールのテンプレートを設定

Firebaseコンソール > Authentication > テンプレートで編集できる。
後からでもOK。

2:HTMLにSDKを追加

前記事で作成したpublicフォルダに、適当なhtmlファイルを作る。
Javascript用のSDKを読み込むには、HTMLの<Head><script>を追加すればOK。

<!-- CDNからSDKを追加 -->
<script defer src="/__/firebase/6.2.4/firebase-app.js"></script>

<!-- ページが読み込まれたら、必要なサービスのみを読み込む -->
<script defer src="/__/firebase/6.2.4/firebase-auth.js"></script>
<script defer src="/__/firebase/6.2.4/firebase-firestore.js"></script>

<!-- 初期設定 jsを読み込む-->
<script defer src="/__/firebase/init.js"></script>

謎のパス "/__/"

この "/__/"というパスは、一体なんやねん?ということで検索してみた。
予約済み URL から Firebase SDK を読み込む  |  Firebase

Firebase Hostingが予約したURLらしいです。名前空間の予約ってどこでできるんやろ?と一瞬だけ検索してみたが有識者以外立ち入り禁止の雰囲気を察知して、そっと閉じました。
このURL部分、公式リファでも<script src="https://www.gstatic.com/firebasejs/5.10.1/firebase-app.js"></script>こんな風に書いてる場合もあるのだけど、 私が思うに、予約済みURLとやらを導入したのは最近で、リファレンスの更新が間に合ってない(または、古い記事を検索してしまっている)場合もあるのではないかと。
さらに、いろんなプログラム言語に向けた解説があるので、検索してヒットしたページを鵜呑みにするとエラーが出て進まない!ってなるのかなぁと思う。

初期設定について

初期設定も、このタグを貼れだとか、このスクリプトをコピペしろとか、書いてることがバラバラだなぁという印象を受けるんだけど、おそらく<script defer src="/__/firebase/init.js"></script>この一行で初期化は済んでると思われる。 これも2019/07/12現在の話で、また変わるのかもしれない。

deferの意味

ページを読み込んでからSDKを読み込む場合はdeferをつければいいらしい。
そうでない場合は、省く。

3:メアドを入力して確認メールを送信するまで

SDKをインストールできているので、あとはリファレンスを参照しつつ書くだけ。

function SignIn(){

    //第一引数
    var email = document.getElementById('email').value;

    //第二引数
    var actionCodeSettings = {

      // 確認メールに埋め込むリンクURL
      url: window.location.href,

      // This must be true. と公式が言うてはります
      handleCodeInApp: true      
        
    };

    //確認メールを送信する
    firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings).then(function() {

        //ローカルストレージにemailを設定する
        window.localStorage.setItem('emailForSignIn', email);

        // アラート表示
        alert( email + 'へメールを送信しました。メール内にあるリンクをクリックしてログインを完了させてください。');

        // サインインのボタンを非表示
        document.getElementById("sign_in").style.display = "none";

    }).catch(function(error) {

        DebugError(error);

    });

}

ローカルストレージにメアドを保持する理由

確認メールのリンクをクリック > 新規でページが開く > ログイン完了のメソッドを実行。このメソッドの引数としてメアドが必要だから。
その処理は後ほど記述。

ブラウザのローカルストレージについてはこちらの記事にて。
ブラウザにデータを保存するlocalStorage(ローカルストレージ)の使い方 | 株式会社グランフェアズ

4:エラー処理用関数を作ってみた

そのままだと、英語でエラーのご案内をしてくださるので、主要なものは日本語にしたくて作ってみた。
エラーコードの一覧は公式SDKリファレンスで見れる。

Error | JavaScript SDK  |  Firebase

function DebugError(error){
    var message;
    switch(error.code){
        case "auth/invalid-email":
            message = "メールアドレスを設定してください。"
            break;
        case "auth/invalid-action-code":
            message = "メールのリンクが期限切れ、または既に使用されているため無効です。メールアドレスを設定し、再度ログインしてください。"
            break;
        default:
            message = error.message;
            break;
    }
    
    alert('Error: ' + error.code +'\n' + message);
    console.log(error);
    //ローカルストレージを消す
    window.localStorage.removeItem('emailForSignIn');
}

5:確認メールのリンクを押して、戻った時の処理と初期設定

この例では、同ページのURLを設定しているので、新たにこのページが読み込まれた時の初期設定に記述する。

//ページが読み込まれたら初期設定を実行
document.addEventListener("DOMContentLoaded", function(){

    initApp();

});

//初期設定
function initApp(){

    //メールアドレスをローカルストレージから取得して表示する
    var email = window.localStorage.getItem('emailForSignIn');
    if(email){
        document.getElementById('email').value = email;  
    }
    
    //ログイン状態を調べる
    firebase.auth().onAuthStateChanged(function(user) {
        if (user) {    //ログイン中なら

            SetDisplay();

        }else{  //ログアウト中なら ←確認メールから戻った時はまだこの状態

            CompleteSignIn(email);

        }
    }); 
  
}

//ログインを完了
function CompleteSignIn(email){

    //リンクがメールリンクと一致するかどうかを調べる
    if (firebase.auth().isSignInWithEmailLink(window.location.href)) {

        if(!email){
            email = window.prompt('確認のためにメールアドレスを入力してください。');
            window.localStorage.setItem('emailForSignIn', email);
        }

        //完了処理
        firebase.auth().signInWithEmailLink(email, window.location.href).then(function(result) { 

            //表示処理
            SetDisplay();

        }).catch(function(error) {

            //エラー出力
            DebugError(error);

        });

    }

    //ブラウザの履歴のURLを置き換える
    if (history && history.replaceState) {
        window.history.replaceState({}, document.title, window.location.href.split('?')[0]);
    }
}

//表示切り替えなどの処理はここで
function SetDisplay(){
    //ログイン状態の場合
    firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
            //ログイン中
        }else{
            //ログアウト中
        }
    });

}

ブラウザのURLを書き換える理由

確認メールのリンクは、戻りページのURLの後ろに変数をくっつけたものになってるので、変数を省くため。
Firebase側で、リンクを作成して送信し、変数の確認もしてくれる。

6:ログアウト処理

function SignOut(){
    firebase.auth().signOut().then(function() {
        console.log("ログアウトしました");
        SetDisplay();
    }).catch(function(error) {
        DebugError(error);
    });
}

一連の処理はこんな感じ。
あとはボタンとか入力フォームなどに紐付けすればOK.

メソッドまとめ

確認メールの送信

//第一引数
var email = document.getElementById('email').value;

//第二引数
var actionCodeSettings = {
  // 確認メールに埋め込むリンクURL
  url: window.location.href,
  // This must be true. 
  handleCodeInApp: true              
};

//確認メールの送信
firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings).then(function() {
    //成功
}).catch(function(error) {
    //失敗
});

リンクURLと現在のページのURLが一致するかどうかを調べる

戻り値:bool

firebase.auth().isSignInWithEmailLink(現URL)

ログインを完了させる

第一引数:メールアドレス
第二引数:リンクURL(=現URL)

firebase.auth().signInWithEmailLink(email, window.location.href).then(function(result) { 
    //成功
}).catch(function(error) {
    //失敗
});

ログアウト

firebase.auth().signOut().then(function() {
    //成功
}).catch(function(error) {
    //失敗
});

ログイン状態を調べる

firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        //ログイン中
    }else{
        //ログアウト中
    }
}); 

ユーザー情報を取得する

取得できる情報は公式にて: ユーザー管理  |  Firebase

f:id:nico-taniku:20190713083544p:plain:w600

firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        //ログイン中
        console.log(user);
        console.log("uid="+user.uid);
        console.log("email="+user.email);
        console.log("displayName="+user.displayName);
        console.log("photoURL="+user.photoURL);
        console.log("phoneNumber="+user.phoneNumber);
        console.log("emailVerified="+user.emailVerified);
                 
    }else{
        //ログアウト中
    }
}); 

以上。