🔥

Rails7のimportmapでfirebaseuiを使ったOAuthを実装

2022/11/02に公開

前提

  • Firebase コンソールでアプリの設定済み

環境

$ ruby -v
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux]
$ rails -v
Rails 7.0.4

実装

importmapに必要なものを追加する

  • firebaseui
$ bin/importmap pin firebaseui
Pinning "firebaseui" to https://ga.jspm.io/npm:firebaseui@6.0.1/dist/esm.js
Pinning "@firebase/app" to https://ga.jspm.io/npm:@firebase/app@0.8.3/dist/esm/index.esm2017.js
Pinning "@firebase/app-compat" to https://ga.jspm.io/npm:@firebase/app-compat@0.1.38/dist/esm/index.esm2017.js
Pinning "@firebase/auth-compat" to https://ga.jspm.io/npm:@firebase/auth-compat@0.2.24/dist/index.esm2017.js
Pinning "@firebase/auth/internal" to https://ga.jspm.io/npm:@firebase/auth@0.20.11/dist/esm2017/internal.js
Pinning "@firebase/component" to https://ga.jspm.io/npm:@firebase/component@0.5.21/dist/esm/index.esm2017.js
Pinning "@firebase/logger" to https://ga.jspm.io/npm:@firebase/logger@0.3.4/dist/esm/index.esm2017.js
Pinning "@firebase/util" to https://ga.jspm.io/npm:@firebase/util@1.7.3/dist/index.esm2017.js
Pinning "dialog-polyfill" to https://ga.jspm.io/npm:dialog-polyfill@0.4.10/dialog-polyfill.js
Pinning "firebase/compat/app" to https://ga.jspm.io/npm:firebase@9.13.0/compat/app/dist/index.esm.js
Pinning "firebase/compat/auth" to https://ga.jspm.io/npm:firebase@9.13.0/compat/auth/dist/index.esm.js
Pinning "idb" to https://ga.jspm.io/npm:idb@7.0.1/build/index.js
Pinning "material-design-lite/src/button/button" to https://ga.jspm.io/npm:material-design-lite@1.3.0/src/button/button.js
Pinning "material-design-lite/src/mdlComponentHandler" to https://ga.jspm.io/npm:material-design-lite@1.3.0/src/mdlComponentHandler.js
Pinning "material-design-lite/src/progress/progress" to https://ga.jspm.io/npm:material-design-lite@1.3.0/src/progress/progress.js
Pinning "material-design-lite/src/spinner/spinner" to https://ga.jspm.io/npm:material-design-lite@1.3.0/src/spinner/spinner.js
Pinning "material-design-lite/src/textfield/textfield" to https://ga.jspm.io/npm:material-design-lite@1.3.0/src/textfield/textfield.js
  • @firebase/auth
$ bin/importmap pin @firebase/auth
Pinning "@firebase/auth" to https://ga.jspm.io/npm:@firebase/auth@0.20.11/dist/esm2017/index.js
Pinning "@firebase/app" to https://ga.jspm.io/npm:@firebase/app@0.8.3/dist/esm/index.esm2017.js
Pinning "@firebase/component" to https://ga.jspm.io/npm:@firebase/component@0.5.21/dist/esm/index.esm2017.js
Pinning "@firebase/logger" to https://ga.jspm.io/npm:@firebase/logger@0.3.4/dist/esm/index.esm2017.js
Pinning "@firebase/util" to https://ga.jspm.io/npm:@firebase/util@1.7.3/dist/index.esm2017.js
Pinning "idb" to https://ga.jspm.io/npm:idb@7.0.1/build/index.js
Pinning "tslib" to https://ga.jspm.io/npm:tslib@2.4.1/tslib.es6.js

firebaseuiのスタイルシートを追加する

app/views/layouts/application.html.erb
  <%# ... %>

  <%= stylesheet_link_tag "application" %>
+  <%= stylesheet_link_tag 'https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.css'%>
  <%= javascript_importmap_tags %>

  <%# ... %>

stimulusのコントローラーを作成する

初期化関係の処理は公式ドキュメントに書かれている通りに書いていきます。
https://firebase.google.com/docs/auth/web/firebaseui?hl=ja&authuser=0
今回はログイン処理だけなのでconnect()の中で初期化しましたが、ログアウトやユーザー情報の取得などで再利用すると思うので、適当に共通化したほうがいいと思います。

app/javascript/controllers/login_controller.js
import { Controller } from "@hotwired/stimulus";
import { initializeApp } from "@firebase/app";
import { getAuth, GoogleAuthProvider } from "@firebase/auth";
import * as firebaseui from "firebaseui";

export default class extends Controller {
  static targets = ["firebaseuiAuthContainer"];

  connect() {
    const firebaseConfig = {
      apiKey: "[YOUR API KEY]",
      authDomain: "[YOUR AUTH DOMAIN]",
      projectId: "[YOUR PROJECT ID]",
      storageBucket: "[YOUR STORAGE BUCKET]",
      messagingSenderId: "[YOUR MESSAGING SENDER ID]",
      appId: "[YOUR APP ID]",
    };

    // firebaseを初期化
    initializeApp(firebaseConfig);

    // firebase UIを初期化
    const auth = getAuth()
    const ui = new firebaseui.auth.AuthUI(auth);

    // ターゲット「firebaseuiAuthContainer」にログインUIを表示する
    ui.start(this.firebaseuiAuthContainer, {
      // Google以外のプロパイダでの認証を実装する場合は、他のプロパイダIDを追加する
      signInOptions: [GoogleAuthProvider.PROVIDER_ID],
    });
  }
}

viewを作成する

ログイン機能を実装したいviewに書いていきます。
firebaseuiAuthContainerの中にログインのUIが表示されます。

<h1>ログイン</h1>
<div data-controller="login">
  <div data-login-target="firebaseuiAuthContainer"></div>
</div>

完成

これでfirebaseuiが実装できました。
ログインしたユーザーの情報はonAuthStateChangedで取得できます。
https://firebase.google.com/docs/auth/web/manage-users?hl=ja&authuser=0#get_the_currently_signed-in_user

onAuthStateChanged(auth, (user) => {
  if (user) {
    console.log(user)
  } else {
    console.log('未ログイン')
  }
});

参考

https://github.com/rails/importmap-rails
https://firebase.google.com/docs/auth/web/firebaseui?hl=ja&authuser=0
https://firebase.google.com/docs/auth/web/manage-users?hl=ja&authuser=0#get_the_currently_signed-in_user

Discussion