[Firebase] Authenticationで複数の認証プロバイダへ同時対応する (Web編)

今まではFirebaseの個別の認証プロバイダでログインしていましたが、今回はここまで対応した全プロバイダのいずれかでログインできる仕組みを作ってみます。

以下の画面のように複数の認証方法から自由に選択することができます。

Authenticationの複数プロバイダ同時対応

Firebase Webコンソールの設定

FirebaseのWebコンソールへログインしたら、メニュー「Authentication」→「ログイン方法」とたどります。

アコーディオンの中で対応したいプロバイダを「有効」にして回ります。

認証プロバイダごとに設定が必要です。詳しくは各記事を参照ください。

FacebookやTwitterは向こうのサイトでの手続きが色々合って若干面倒ですね。Googleや電話番号、メールあたりはFirebase上だけで設定が完結するのでとりえあえず試してみたい場合など非常に楽です。PlayゲームとGameCeterはスマートフォン用のネイティブアプリを開発する際に用いますので、ここでは割愛します。

ソースコード

config.js

いつものやつです。FirebaseのWebコンソールに表示されたものをそのままコピペします。

// コンソールの内容をそのままコピペ
var config = {
  apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  authDomain: "test-f76bc.firebaseapp.com",
  databaseURL: "https://test-f76bc.firebaseio.com",
  projectId: "test-f76bc",
  storageBucket: "test-f76bc.appspot.com",
  messagingSenderId: "0000000000000"
};
firebase.initializeApp(config);

index.html

FirebaseUIを利用します。HTML部分は今回はこのファイルだけです。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Firebase Auth</title>
  <link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css" />
  <style type="text/css">
    h1{text-align:center;}
    #info{text-align:center;}
    #logout{text-align:center;}
    .hide{display:none;}
  </style>
</head>
<body>
  <h1>Firebase Auth Sample</h1>
  <div id="info"></div>
  <div id="firebaseui-auth-container"></div>
  <div id="logout" class="hide">
      <form><button type="button" id="btn-logout">ログアウト</button></form>
  </div>

  <script src="https://www.gstatic.com/firebasejs/5.8.1/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/5.8.1/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/ui/3.5.2/firebase-ui-auth__ja.js"></script>
  <script src="/js/config.js"></script>
  <script>
    //----------------------------------------------
    // Firebase UIの設定
    //----------------------------------------------
    var uiConfig = {
        // ログイン完了時のリダイレクト先
        signInSuccessUrl: '/auth/multi/',

        // 利用する認証機能
        signInOptions: [
          firebase.auth.GoogleAuthProvider.PROVIDER_ID,
          firebase.auth.FacebookAuthProvider.PROVIDER_ID,
          firebase.auth.TwitterAuthProvider.PROVIDER_ID,
          firebase.auth.GithubAuthProvider.PROVIDER_ID,
          firebase.auth.EmailAuthProvider.PROVIDER_ID,
          {provider:firebase.auth.PhoneAuthProvider.PROVIDER_ID, defaultCountry:'JP'},
          firebaseui.auth.AnonymousAuthProvider.PROVIDER_ID
        ],

        // 利用規約のURL(任意で設定)
        tosUrl: 'http://example.com/kiyaku/',
        // プライバシーポリシーのURL(任意で設定)
        privacyPolicyUrl: 'https://miku3.net/privacy.html'
    };

    //----------------------------------------------
    // ログイン状態のチェック
    //----------------------------------------------
    firebase.auth().onAuthStateChanged( (user) => {
      // ログイン済み
      if(user) {
        showLogin('Login Complete!', `${user.displayName}さんがログインしました<br>(${user.uid})`);
        console.log(user);
      }
      // 未ログイン
      else {
        var ui = new firebaseui.auth.AuthUI(firebase.auth());
        ui.start('#firebaseui-auth-container', uiConfig);
      }
    });

    //----------------------------------------------
    // ログアウト
    //----------------------------------------------
    document.querySelector('#logout').addEventListener("click", ()=>{
      firebase.auth().signOut().then(()=>{
          showLogout("Firebase Auth Sample", "");
        })
        .catch( (error)=>{
          alert(`ログアウトできませんでした(${error})`);
        });
    });

    /**
     * ログイン時の各種表示
     */
    function showLogin(title, msg){
      document.querySelector('h1').innerHTML    = title;
      document.querySelector('#info').innerHTML = msg;
      document.querySelector('#logout').classList.remove("hide");
    }

    /**
     * ログアウト時の各種表示
     */
     function showLogout(title, msg){
      document.querySelector('h1').innerHTML    = title;
      document.querySelector('#info').innerHTML = msg;
      document.querySelector('#logout').classList.add("hide");
    }
  </script>
</body>
</html>

実行結果

以下のページから各種ログインを試すことができます。 miku3.net

解説

プロバイダ毎に設定を行いたい

signInOptionsで行うことができます。例えば今回だと電話番号(SMS)認証で行っている箇所がそれにあたります。

    var uiConfig = {
        signInOptions: [
          firebase.auth.GoogleAuthProvider.PROVIDER_ID,
          firebase.auth.FacebookAuthProvider.PROVIDER_ID,
          firebase.auth.TwitterAuthProvider.PROVIDER_ID,
          firebase.auth.GithubAuthProvider.PROVIDER_ID,
          firebase.auth.EmailAuthProvider.PROVIDER_ID,
          {provider:firebase.auth.PhoneAuthProvider.PROVIDER_ID, defaultCountry:'JP'},
          firebaseui.auth.AnonymousAuthProvider.PROVIDER_ID
        ]
    };

単純にその認証プロバイダの箇所だけハッシュ(連想配列)とし、オプションを指定するだけです。

{
    provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID
  , // (ここにオプションを定義していく)
}

ポップアップでログインさせたい

uiConfigsignInFlowの指定を追加するとポップアップウィンドウが新たに立ち上がり認証されます。ログイン後は元のウィンドウにもどってきます。

    var uiConfig = {
        signInFlow: 'popup'
        //(省略)
    }

ブラウザのポップアップブロッカーが動作する可能性も考えられるので、注意書きなどをした方が良いかもしれません。

取得できるユーザー情報

項目 説明
user.uid Firebaseで発番されたユーザーID
user.displayName 表示用のユーザー名
user.email メールアドレス
user.emailVerified メールアドレスの存在確認済みか(trueなら確認済み)
user.phoneNumber 電話番号
user.photoURL アバター画像のURL

ログインに利用したプロバイダによって異なります。 user.uidはいずれのプロバイダでも取得できますが、例えば匿名認証でログインした場合には他の項目はそのままでは一切取得できません。入力してもらってないので当然と言えば当然なのですが。

どの認証プロバイダか判定したい

ログインした際に渡されるuserproviderDataを除くと、どの認証プロバイダでログインされたか、また認証プロバイダ毎のユーザー情報を確認することができます。

firebase.auth().onAuthStateChanged( (user) => {
  if(user) {
    console.log( user.providerData );
  }
});

実際に動かしてみるとわかるのですが、user.providerDataは単なる配列です。 以下はTwitterでログインした場合。

つまりuser.providerData[0].providerIdを見ればどの認証プロバイダを利用しているかが判定できます。

認証方法 providerId
メール/パスワード "password"
電話番号 "phone"
Google "google.com"
Facebook "facebook.com"
Twitter "twitter.com"
GitHub "github.com"

匿名でログインした場合はuser.providerData自体が空の状態になります。

また以下はGoogleでログインした際にFacebookでもログインしていたため、自動的に2つのアカウントがFirebase上で紐付けられ2つの要素が返ってきました。

ちなみにuser.uidはFirebaseから発行された物ですが、user.providerData[i].uidは各認証プロバイダから発行された物です。うっかり間違えると大変なことになる場合がありますのでここは勘違いなきようお気をつけください。

参考ページ

firebase.google.com github.com