Firebaseの続きです。前回はRealtime DatabaseにFetch APIでCRUD操作しました。作ってみて気がついたがこのままだと誰でもデータを編集できちゃう。そうなってくると必要なのはユーザー認証設定。Authenticationで実現できるようなのでトライ。ドキュメキュメントにはなかったリダイレクト設定も調べて実現しました。それではいきましょう!
【目次】
※参考:前回記事
【Firebase】Realtime DatabaseにFetch APIでCRUD操作する - クモのようにコツコツと
※参考:Web開発環境についてのまとめ(随時更新)
qiita.com
前回のおさらい
Realtime DatabaseにFetch APIでCRUD操作できた!
- Create(追加):POST
- Read(取得):GET
- Update(更新):UPDATE
- Delete(削除):DELETE
サーバ側の設定をしていないがあらかじめRealtime Database側にレスポンスを返す設定が用意されているということだ!
詳細は前回記事を参照
※参考:【Firebase】Realtime DatabaseにFetch APIでCRUD操作する - クモのようにコツコツと
ただ、このままだと誰でもデータを編集できてしまう。そうなってくると次に欲しいのはユーザー認証機能。
Authenticationコンソールの設定
ユーザー追加設定
ユーザー認証はFirebaseのAuthentication*1というプロダクトで実現できる。
Firebaseのコンソールで「Authentication」を開く(「Users」タブ)。
今回はユーザーの追加/削除を作らずログイン/ログアウトだけを検証したい。この画面であらかじめゲストユーザーを作っておこう。
ゲストユーザーが追加された*2!なるほど、Firebase側で「ユーザー UID」を追加してユーザーを認識するんだ。これによってユーザーのパスワードは管理者には見せない仕組みになっている。
ユーザー設定の変更
一番右の三点アイコンでオプション設定が開く
パスワードの再設定、アカウント無効、アカウント削除がある
パスワードの再設定はメアドにメールが送られるようだ。これによってユーザーだけがパスワードを編集できる。
アカウント無効は管理者側でできる
アカウント削除も管理者側でできる
メール認証を有効にする
次に「Sign-in method」タブを開く。おお、メール、Google、Twitterなどいろんな認証設定がある! 今回はシンプルそうな「メール/パスワード」から体験したい。
初期は全て「無効」だが、カーソルを載せると鉛筆アイコンで変更できる
「メール/パスワード」の変更画面
「有効」にして保存
「メール/パスワード」だけが有効になった!
参考ドキュメント
ここからコード作成に入る。基本的にはドキュメントを参考に進める。
※参考:ウェブサイトで Firebase Authentication を使ってみる
※参考:JavaScript でパスワード ベースのアカウントを使用して Firebase 認証を行う
しかし、メール/パスワード認証のドキュメントは肝心の処理内容が空っぽだったりして詳細情報を調べるのに苦心した。*3
ドキュメントに埋め込まれているこちらの動画、作業の流れがイメージしやすかった♪ www.youtube.com
HTMLページ
ログインページを作る
新規で「login.html」というページを作る。
※参考:firebase-hosting-test/login.html at main · ryo-i/firebase-hosting-test · GitHub
入力フォームとログインボタン
<section> <h1>今日の一句へのログイン</h1> <p>ログインしてください。</p> <label> Email<input type="text" name="email" size="30" maxlength="30" class="email"> </label> <label> Pass<input type="password" name="pass" size="30" maxlength="30" class="pass"> </label> <input type="button" value="ログイン" class="loginBtn"> </section>
.email
にメアド、. pass
にパスを入力し、.loginBtn
ボタンを押すとログインできるようにする。
bodyタグの最後にfirebase系のリンクを追加
<!-- update the version number as needed --> <script defer src="/__/firebase/8.2.1/firebase-app.js"></script> <!-- include only the Firebase features as you need --> <script defer src="/__/firebase/8.2.1/firebase-auth.js"></script> <script defer src="/__/firebase/8.2.1/firebase-analytics.js"></script> <!-- initialize the SDK after all desired features are loaded, set useEmulator to false to avoid connecting the SDK to running emulators. --> <script defer src="/__/firebase/init.js?useEmulator=true"></script> <script src="js/auth.js"></script>
- 「firebase-app.js」はFirebase本体
- 「firebase-auth.js」はAuthentication本体
- 「firebase-analytics.js」はGoogleアナリティクス設定
- 「init.js」はこのアプリ固有の初期化情報
- 「auth.js」は今回新たに作るログイン設定のファイル
以前、Realtime Databaseの時に初期化情報をコメントアウトしても動いたのは「init.js」に初期化情報が書かれているからだった!
※参考:【Firebase】Realtime Databaseにブラウザから直接CRUD操作する - クモのようにコツコツと
ログアウトボタンを作る
前回作った「今日の一句」ページ「fetch.html」にログアウトボタンを追加する。
※参考:firebase-hosting-test/fetch.html at main · ryo-i/firebase-hosting-test · GitHub
<p>現在ログイン中です。</p> <input type="button" value="ログアウト" class="logoutBtn">
.logoutBtn
ボタンを押すとログアウトしてログインページにリダイレクトさせたい。さらにログアウト中にこのページにアクセスしてもログインページにリダイレクトされるようにしたい。
bodyタグの最後
<!-- update the version number as needed --> <script defer src="/__/firebase/8.2.1/firebase-app.js"></script> <!-- include only the Firebase features as you need --> <script defer src="/__/firebase/8.2.1/firebase-auth.js"></script> <script defer src="/__/firebase/8.2.1/firebase-analytics.js"></script> <!-- initialize the SDK after all desired features are loaded, set useEmulator to false to avoid connecting the SDK to running emulators. --> <script defer src="/__/firebase/init.js?useEmulator=true"></script> <script src="js/auth.js"></script> <script src="js/fetch.js"></script>
こちらには前回作ったFetch APIのCRUD操作設定の「fetch.js」があったが、それに加えてFirebaseのファイルと「auth.js」のリンクも追加する。
JSコード
ここからはJSコード。新規で「auth.js」を作成
※参考:firebase-hosting-test/auth.js at main · ryo-i/firebase-hosting-test · GitHub
DOMContentLoadedイベント(DOM読み込み後に実行)
処理の全体を下記のイベントで囲う。
document.addEventListener('DOMContentLoaded', () => { // 処理内容 });
処理を普通に書くと「firebase-app.js」や「firebase-auth.js」で定義されているfirebase.auth()
が認識されなかった。
そのため全体をDOMContentLoaded
のイベントで囲って、DOM(およびbodyタグ内にscriptタグでリンクされているJSファイル)が全部読み終わってから処理を実行するようにしたら、認識された。
scriptタグに書かれているdefer
属性が処理順番に影響しているようだった。
※参考:<script> タグに async / defer を付けた場合のタイミング - Qiita
DOM取得
// DOM const email = document.querySelector('.email'); const pass = document.querySelector('.pass'); const loginBtn = document.querySelector('.loginBtn'); const logoutBtn = document.querySelector('.logoutBtn');
- 変数
email
で.email
を取得 - 変数
pass
で.pass
を取得 - 変数
loginBtn
で.loginBtn
を取得 - 変数
logoutBtn
で.logoutBtn
を取得
先ほど「login.html」と「fetch.html」に作ったログイン/ログアウトにつかうDOMを取得する
ログイン状態のチェック
「fetch.html」のページを開いた時にログインチェックを行い、ログアウトしていたらログインページ「login.html」にリダイレクトさせる。
// Login Check const loginCheck = () => { const pathname = window.location.pathname; console.log(pathname); firebase.auth().onAuthStateChanged((user) => { if (user) { console.log('ログイン済み!'); if (pathname === '/login.html') { window.location.replace('fetch.html'); } } else { console.log('未ログイン!'); if (pathname === '/fetch.html') { window.location.replace('login.html'); } } }); }; loginCheck();
- 変数
loginCheck
の値はアロー関数 - 変数
pathname
でページのパスpathname
を取得(コンソールにパスを表示) firebase.auth()
のonAuthStateChanged()
メソッドを実行、引数はアロー関数で引数はuser
- もし
user
が認識されたらコンソールに「ログイン済み!」と表示
もしパスが/login.html
だったらwindow.location
でfetch.html
にリダイレクト user
が認識されなかったらコンソールに「未ログイン!」と表示
もしパスが/fetch.html
だったらwindow.location
でlogin.html
にリダイレクトloginCheck()
実行(ページ読み込み時)
ログイン状態のチェックについてはこちらのドキュメントにあった。onAuthStateChanged()
でチェックする
しかし、ドキュメントだとチェック後の処理が空っぽでリダイレクトさせる方法がよくわからなかったw
調べるとそのものズバリなQAを発見!普通にJSのwindow.location
を使えばいいのかな?
※参考:Firebaseログイン後のページへのリダイレクト - Javascript
こちらはVue/Nuxt環境での事例だが、実際にwindow.location
を使って実現している!
※参考:Nuxt/VuexでFirebase Authenticationを使ってユーザー認証機能を作る - フリーランチ食べたい
ということで自分もこの方法を取ることにした。
window.location
でリダイレクトしたあとにブラウザの「戻る」ボタン押すと戻れちゃった、、
リダイレクトがブラウザの履歴に残ってしまうようだ。replace()
を追加したら回避できた♪
※参考:ブラウザの戻るボタンを押せなくする(ブラウザバック禁止) - Qiita
なお、こちらのドキュメントでlinkWithRedirect()
というメソッドを見つけたが、この方法だと動かなかった。
※参考:JavaScript を使用してアカウントに複数の認証プロバイダをリンクする | Firebase
これはGoogleなどの外部プロバイダの認証ページから戻るためのメソッドのようだ。
※参考:User | JavaScript SDK | Firebase
ログイン処理
ログイン処理を作る
// Login Event const login = () => { const emailVal = email.value; const passVal = pass.value; firebase.auth().signInWithEmailAndPassword(emailVal, passVal) .then((user) => { console.log('ログイン成功!'); loginCheck(); }) .catch((error) => { const errorCode = error.code; const errorMessage = error.message; console.log('ログイン失敗!'); console.log(errorCode); console.log(errorMessage); alert('ログインに失敗しました'); }); };
- 変数
login
の値はアロー関数 - 変数
emailVal
でemail
の入力値を取得 - 変数
passVal
でpass
の入力値を取得 firebase.auth()
でsignInWithEmailAndPassword()
メソッドを実行(引数はemailVal
,passVal
)then()
でログイン成功時の処理を(引数はuser
) コンソールに「ログイン成功!」とuser
情報を表示loginCheck()
を実行(リダイレクト)catch()
でエラー処理を設定(引数はerror
) 変数errorCode
でエラーコードを取得
変数errorMessage
でエラーメッセージを取得
コンソールで「ログイン失敗!」とエラーコード、エラーメッセージを表示
アラートで「ログインに失敗しました」表示
ログイン成功するとloginCheck()
でリダイレクトする。ログイン失敗はアラートでわかるようにした。
メールアドレス/パスワードの方法はこちらのドキュメント
※参考:JavaScript でパスワード ベースのアカウントを使用して Firebase 認証を行う
signInWithEmailAndPassword()
でログインできる(長い名前w)
※参考:Auth | JavaScript SDK | Firebase
ドキュメントではログイン後の処理内容がまたしても空っぽw
やりたいことはページのリダイレクトだったので先ほどのloginCheck()
の方法を調べた次第。
ログインボタンのクリックイベント
if (loginBtn) { loginBtn.addEventListener( 'click', login, false ); }
- もし
loginBtn
が存在したらloginBtn
をクリックしたときlogin
を実行
loginBtn
が「fetch.html」ページでは存在しないため、このページではエラーになった。そのため、if文でloginBtn
の存在を判定してから実行するようにした。
ログアウト処理
ログイン後、ログアウトもできるようにしたい。ログアウトボタンでログアウトする((できれば一定時間が経ったらログアウト、とかもしたいが今回は調べきれず)。
先ほどのログインボタンイベントがベース(処理は少ない量だったのでそのまま中に書いた)。
// Logout Event if (logoutBtn) { logoutBtn.addEventListener( 'click', () => { firebase.auth().signOut(); loginCheck(); }, false ); }
- もし
logoutBtn
が存在したらlogoutBtn
をクリックした時に
firebase.auth()
のsignOut()
メソッドを実行
loginCheck()
を実行
こちらもlogoutBtn
が「login.html」に存在しないのでif文で存在を判定してから実行。
ログアウトはsignOut()
で実行される。こちらは短い名前w
※参考:Auth | JavaScript SDK | Firebase
ログアウト後にloginCheck()
を実行してログインページにリダイレクト
なお、今回はやってないがログイン後にユーザー情報も取得できそう。
例えば「こんにちは○○さん」とアカウント名を表示したり、「○○さんの投稿一覧」だけをピックアップしたり、ページの内容を動的に変更できる。
ブラウザ挙動
ログアウト状態で「fetch.html」にアクセスすると
※参考:今日の一句ページ Realtime DatabaseにFetch APIでCRUD
ログインページ「login.html」にリダイレクトされる。
※参考:ログインページ
Realtime DatabaseにFetch APIでCRUD
Authenticationのコンソールで設定したゲストユーザーのメール/パスワードを入れる
ゲストユーザーのメール/パスワードは下記
- Email: guest@guest.test
- Pass: guest001
「ログイン」ボタンを押すと「今日の一句」ページにリダイレクトされる
※参考:Realtime DatabaseにFetch APIでCRUD
「ログアウト」ボタンを押すと再びログインページにリダイレクトされる
※参考:ログインページ
Realtime DatabaseにFetch APIでCRUD
全然違うメール/パスワードを入れてみる
「ログインに失敗しました」のアラートが出る
ソース(GitHub)
※参考:ログイン機能JS
firebase-hosting-test/auth.js at main · ryo-i/firebase-hosting-test · GitHub
※参考:ログインページHTML
firebase-hosting-test/login.html at main · ryo-i/firebase-hosting-test · GitHub
※参考:ログアウトボタンHTML
firebase-hosting-test/fetch.html at main · ryo-i/firebase-hosting-test · GitHub
最後に
ということでFirebaseのAuthenticationを使ってメール/パスワードによるユーザー認証設定を作ることができました!
ちょっとした体験版などでゲストユーザーによるログイン機能を作るならこれで十分な気がしますね。いきなり個人情報(メアド、Googleアカウント、SNSアカウントなど)を入れるのは抵抗がある人もいると思うので。
Firebaseのメール/パスワード認証のドキュメントではログイン判定以外の処理内容は空っぽだったのでw、その中に入れるリダイレクト設定の参考になれば幸甚です。
今後、Google認証やTwitter認証なども試してみたく思います。それではまた!
※参考:Web開発環境についてのまとめ(随時更新)
qiita.com