このガイドは、「React Web アプリケーションで Firebase Authentication を設定する方法」の補足です。このガイドの導入部分で、Firebase が基本的なメール/パスワード認証以外の認証スキームを提供していることに注意しました。それらの代替手段の 1 つは、パスワードレス認証です。
パスワードレス認証は、アプリケーションを構築する際の魅力的なオプションです。ユーザーはパスワードを覚えておく必要がなく、パスワードを紛失することを心配する必要もないため、ユーザー エクスペリエンスが簡素化されます。また、パスワードのキャプチャや管理ロジックを設計する必要がないため、開発エクスペリエンスも容易になります。
このガイドでは、Firebase のパスワードなしの認証を実装する、単純なログイン/確認/プロファイル/ログアウト ワークフローを構築します。
Google は Firebase Authentication のさまざまな制限を設定しています。無料のSparkプランを使用している場合は、サインイン リンク メールが 1 日あたり 5 通に制限されることに注意してください。 Spark プランはテスト目的には十分かもしれませんが、この制限を超えるには従量課金制のBlazeプランにアップグレードする必要があります。
このガイド全体を通じて、 「React Web アプリケーションで Firebase Authentication を設定する方法」ガイドを前提条件ガイドとして参照し、関連するプロジェクトを前提条件プロジェクトとして参照します。
このガイドを完了するには、次のものが必要です。
前提条件ガイドでは、基本的なメール/パスワード認証用の新しい Firebase プロジェクトを作成しました。次に、同じプロジェクトでパスワードなしの認証を有効にします。 Firebase アカウントにログインし、 [コンソールに移動]をクリックします。
Firebase プロジェクト ダッシュボードにリストされている認証プロジェクトをクリックします。このガイドでは、プロジェクト名my-auth-test
を使用します。
左側のパネルメニューで「認証」をクリックします。
メイン ウィンドウで[サインイン方法]タブをクリックします。
前提条件ガイドでの作業により、 「サインイン プロバイダー」テーブルの「プロバイダー」列の下に「電子メール/パスワード」がすでに「有効」のステータスで表示されているはずです。鉛筆アイコンをクリックして、電子メール/パスワードプロバイダーの構成パネルを開きます。
トグルをクリックして、電子メール リンク (パスワードなしのサインイン)を有効にします。
「保存」をクリックします。
これで、Firebase プロジェクトがパスワードなしの認証をサポートするように構成されました。
希望のアプリケーション名を使用して新しい React プロジェクトを作成します。このガイドでは、 passwordless-auth
を使用します。
npx create-react-app passwordless-auth
このガイドでは、3 つの Node.js パッケージのインストールが必要です。
上記の 3 つのパッケージをそれぞれnpm
経由でインストールします。
npm install firebase
npm install react-router-dom
npm install bootstrap
firebase.js
をコピーする前提条件プロジェクトでは、Firebase プロジェクト構成データを使用して Firebase Authentication サービスのインスタンスを作成するfirebase.js
ファイルを作成しました。 firebase.js
ファイルは、Firebase プロジェクトの設定値を含む次の構造になっている必要があります。
import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; const firebaseConfig = { apiKey: "AIzaSyDiUlY68W9Li_0EIkmdGdzD7nvqCT9kHnY", authDomain: "my-auth-test-fbd48.firebaseapp.com", projectId: "my-auth-test-fbd48", storageBucket: "my-auth-test-fbd48.appspot.com", messagingSenderId: "1078604952662", appId: "1:1078604952662:web:5d0b908439cfb5684ab7f7" } const app = initializeApp(firebaseConfig); const auth = getAuth(app); export { auth }
firebase.js
新しい React プロジェクト フォルダーにコピーします。
Firebase プロジェクトの構成を確認する必要がある場合は、左側のパネル メニューで[プロジェクトの概要]の横にある歯車アイコンをクリックします。 [全般]タブがすでに選択されているはずです。 [Web アプリ]パネルを含む[アプリ]セクションまで下にスクロールします。 Web アプリパネル内のnpmオプションはすでに選択されているはずです。プロジェクトの構成値が、表示されたコード ブロックにリストされます。
React アプリケーションは、 App
、 Layout
、 Login
、 Confirm
、 Profile
の 5 つのコンポーネントで構成されます。
App
App
コンポーネントは、ルーティングを含むアプリケーション全体の構造を定義します。 Layout
Layout
コンポーネントは、すべてのルートにわたって一貫性を保つアプリケーション マークアップを指定します。 Login
Confirm
Confirm
ページにルーティングされます。 Profile
Profile
ページにルーティングされます。Profile
ページのログアウト ボタンをクリックして、自分のアカウントからログアウトできます。最終的なsrc
ディレクトリには次のファイルが含まれます。
src |__ index.js |__ firebase.js // Copied from prerequisite project in Step 3. |__ App.js |__ Layout.jsx |__ Login.jsx |__ Confirm.jsx |__ Profile.jsx
reportWebVitals.js
setupTests.js
logo.svg
index.css
App.css
App.test.js
前提条件プロジェクトから新しいプロジェクト フォルダーにindex.js
をコピーします。このガイドでは同じファイルを使用します。 index.js
を再構築する必要がある場合は、前提条件ガイドのステップ 5b.2 を参照するか、以下のコード ブロックをコピーしてください。
Layout.jsx
前提条件プロジェクトから新しいプロジェクト フォルダーにコピーします。このガイドでは同じファイルを使用します。 Layout.jsx
を再構築する必要がある場合は、前提条件ガイドのステップ 5d を参照するか、以下のコード ブロックをコピーしてください。必要に応じて、 Layout.jsx
の<p>
タグ内のプロジェクト テキストをReact With Firebase Passwordless Authentication
または任意のタイトルに更新することができます。
index.js
およびLayout.jsx
ファイルは次のようになります。
// index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import "bootstrap/dist/css/bootstrap.min.css"; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <App /> </React.StrictMode> );
// Layout.jsx import { Outlet } from "react-router-dom"; const Layout = () => { return( <div className = "container-fluid"> <div className = "row justify-content-center mt-3"> <div className = "col-md-4 text-center"> <p className = "lead">React With Firebase Passwordless Authentication</p> </div> <Outlet /> </div> </div> ) } export default Layout
App.js
の構築App.js
ファイルは前提条件プロジェクトのファイルとほぼ同じですが、変更点は 2 行のみです。ファイルの構築を容易にするために、前提条件プロジェクトから新しいプロジェクト フォルダーにApp.js
をコピーします。
ファイルから次のimport
行を削除し、以下のように置き換えます。
// Delete this line: import Signup from "./Signup";
// Replace it with: import Confirm from "./Confirm";
ファイルから次の<Route>
を削除し、以下のように置き換えます。
// Delete this line: <Route path = "/signup" element = { <Signup></Signup> } ></Route>
// Replace it with: <Route path = "/confirm" element = { <Confirm></Confirm> } ></Route>
App.js
を保存します。
完全なファイルは次のようになります。
import Layout from "./Layout"; import Login from "./Login"; import Confirm from "./Confirm"; import Profile from "./Profile"; import { BrowserRouter, Routes, Route } from "react-router-dom"; const App = () => { return ( <BrowserRouter> <Routes> <Route path = "/" element = { <Layout></Layout> }> <Route index element = { <Login></Login> }></Route> <Route path = "/confirm" element = { <Confirm></Confirm> } ></Route> <Route path = "/profile" element = { <Profile></Profile> } ></Route> </Route> </Routes> </BrowserRouter> ) } export default App
前提条件プロジェクトの場合と同様に、 Login
コンポーネントが再びアプリケーションのホーム ルートになることに注意してください。
Login.jsx
のビルドパスワードレス認証の場合、明らかにパスワード フィールドを含める必要はなく、パスワード入力の状態を管理する必要もありません。したがって、ログイン フォームはユーザーの電子メール アドレスを取得するだけで済みます。
src
ディレクトリに新しいLogin.jsx
ファイルを作成します。
次のコードを追加します。
import { useState } from "react"; import { auth } from "./firebase"; import { sendSignInLinkToEmail } from "firebase/auth"; const Login = () => { const [email, setEmail] = useState(""); const [notice, setNotice] = useState(""); const actionCodeSettings = { url: "http://localhost:3000/confirm", handleCodeInApp: true } const callSendSignInLinkToEmail = (e) => { e.preventDefault(); sendSignInLinkToEmail(auth, email, actionCodeSettings) .then(() => { setNotice("An email was sent to your email address. Click the link in the email to login."); }) .catch((error) => { setNotice("An error occurred when sending a login link to your email address: ", error.name); }) } return( <div className = "container"> <div className = "row justify-content-center"> <form className = "col-md-4 mt-3 pt-3 pb-3"> { "" !== notice && <div className = "alert alert-warning" role = "alert"> { notice } </div> } <div className = "form-floating mb-3"> <input type = "email" className = "form-control" id = "exampleInputEmail" placeholder = "[email protected]" value = { email } onChange = { (e) => setEmail(e.target.value) }></input> <label htmlFor = "exampleInputEmail" className = "form-label">Email address</label> </div> <div className = "d-grid"> <button type = "submit" className = "btn btn-primary pt-3 pb-3" onClick = {(e) => callSendSignInLinkToEmail(e)}>Submit</button> </div> </form> </div> </div> ) }
Login.jsx
を保存します。
ユーザーのメール アドレスを取得すると、 Login.jsx
フォームは、Firebase のsendSignInLinkToEmail
メソッドを介して、サインイン リンクを含むメールをユーザーのアドレスに送信します。成功すると、電子メールが送信されたことがユーザーに通知されます。 actionCodeSettings
オブジェクトはパラメーターとしてsendSignInLinkToEmail
メソッドに渡され、ユーザーが電子メールで送信されたサインイン リンクをクリックしたときにルーティングされる URL が含まれていることに注意してください。この場合、URL はApp.js
で指定された/confirm
ルートにマップされます。
Confirm.jsx
をビルドするFirebase のsignInWithEmailLink
メソッドは、サインイン リンクをクリックしたユーザーをサインインするために使用されます。すぐにわかるように、このメソッドはemail
パラメーターを受け取り、 email
の値は、ユーザーがログイン フォーム経由でログインするときに使用した電子メール アドレスと一致する必要があります。 Confirm.jsx
、ユーザーに電子メール アドレスを確認するためのフォームを表示し、その後ユーザーのサインインを試みます。
src
ディレクトリに新しいConfirm.jsx
ファイルを作成します。
次のコードを追加します。
import { useState } from "react"; import { auth } from "./firebase"; import { isSignInWithEmailLink, signInWithEmailLink } from "firebase/auth"; import { useNavigate } from "react-router-dom"; const Confirm = () => { const navigate = useNavigate(); const [email, setEmail] = useState(""); const [notice, setNotice] = useState(""); const callSignInWithEmailLink = (e) => { e.preventDefault(); if (isSignInWithEmailLink(auth, window.location.href)) { signInWithEmailLink(auth, email, window.location.href) .then(() => { navigate("/profile"); }) .catch((error) => { setNotice("An occurred during sign in: ", error.name); }) } } return( <div className = "container"> <div className = "row justify-content-center"> <form className = "col-md-4 mt-3 pt-3 pb-3"> { "" !== notice && <div className = "alert alert-warning" role = "alert"> { notice } </div> } <div className = "form-floating mb-3"> <input type = "email" className = "form-control" id = "exampleConfirmEmail" placeholder = "[email protected]" value = { email } onChange = { (e) => setEmail(e.target.value) }></input> <label htmlFor = "exampleConfirmEmail" className = "form-label">Please confirm your email address</label> </div> <div className = "d-grid"> <button type = "submit" className = "btn btn-primary pt-3 pb-3" onClick = {(e) => callSignInWithEmailLink(e)}>Confirm</button> </div> </form> </div> </div> ) } export default Confirm
Confirm.jsx
を保存します。
isSignInWithEmailLink
メソッドは、まずユーザーが使用しているサインイン リンクが有効かどうかを確認します。有効である場合、 signInWithEmailLink
メソッドが呼び出され、ユーザーがサインインします。繰り返しになりますが、 signInWithEmailLink
メソッドに渡されるemail
値は、ユーザーがログイン フォームで使用した電子メール アドレスと一致する必要があります。ユーザーが新規ユーザー(つまり、初めてサインインする)の場合、Firebase は Firebase Authentication ストアにユーザーを自動的に作成することに注意してください。これは、パスワードなしの認証によって提供される簡素化されたエクスペリエンスのもう 1 つの例です。新しいユーザーのアカウント作成は自動的に処理されます。
Profile.jsx
の構築最後に構築するコンポーネントはProfile.jsx
です。ユーザーは、 Confirm.jsx
経由でサインインに成功すると、このコンポーネントにルーティングされます。ルートはユーザーを電子メール アドレスで歓迎し、ログアウトするボタンを提供します。ログアウトすると、ユーザーはLogin
コンポーネントに戻されます。
src
ディレクトリに新しいProfile.jsx
ファイルを作成します。
次のコードを追加します。
import { auth } from "./firebase"; import { signOut } from "firebase/auth"; import { useNavigate } from "react-router-dom"; const Profile = () => { const navigate = useNavigate(); const logoutUser = async (e) => { e.preventDefault(); await signOut(auth); navigate("/"); } return( <div className = "container"> <div className = "row justify-content-center"> <div className = "col-md-4 text-center"> <p>Welcome <em className = "text-decoration-underline">{ auth.currentUser.email }</em>. You are logged in!</p> <div className = "d-grid gap-2"> <button type = "submit" className = "btn btn-primary pt-3 pb-3" onClick = {(e) => logoutUser(e)}>Logout</button> </div> </div> </div> </div> ) } export default Profile
Profile.jsx
を保存します。React アプリケーションを起動します。
npm start
locahost:3000
に移動します。 Login
フォームが表示されるはずです。
サインインに使用する電子メールを入力し、 [送信]をクリックします。送信が成功すると、サインイン リンクを含む電子メールが電子メール アドレスに送信されたという通知が表示されます。
Sign in to project-1078604952662
のようなものにする必要があります。ここで、13 桁の数字シーケンスは Firebase プロジェクトのmessagingSenderId
を表します (このガイドのステップ 3 を参照)。以下の「オプション」セクションでは、Firebase プロジェクト名を変更して、サインイン リンク メールに「ユーザー フレンドリーな」名前を表示する方法を説明します。ここでは、サインイン リンク電子メールを開いて、サインイン リンクをクリックします。 Confirm
フォームに移動します。
サインイン時に使用した電子メール アドレスをConfirm
フォームに入力します。 「確認」をクリックします。確認が成功すると、 Profile
ページに移動します。
サインアウトするには、 Profile
ページの「ログアウト」ボタンをクリックします。サインアウトが成功すると、 Login
フォームに戻ります。
上記の手順は、アプリケーションのワークフローをキャプチャします。
Firebase から送信されるサインイン リンク メールに、 project-1078604952662
などの代わりに「ユーザー フレンドリーな」名前が表示されるように、プロジェクト名を変更できます。 Firebase アカウントにログインし、 [コンソールに移動]をクリックします。
パスワードレス認証は、アプリケーション開発者の間でますます一般的な選択肢になっているようで、当然のことです。パスワードを管理する必要がないという明らかな利点に加えて、サインイン リンクを送信するプロセス自体が検証であるため、電子メールによる検証も必要ありません。
前提条件のプロジェクトと同様に、ここでの実装は基本的なものです。次のような単純な機能拡張を検討することもできます。
特定の電子メール アドレス ドメイン (つまり、一般的なスパム電子メール ドメイン) をブロック/ブラックリストに登録します。
Login
ページでユーザーが入力した電子メール アドレスをローカルに保存し、 Confirm
ページで電子メール アドレスの存在を確認します。このアプローチでは、ユーザーがLogin
ページにアクセスしたのと同じデバイスでサインイン リンクをクリックした場合、電子メール アドレスは回復されるため、 Confirm
ページで再度入力する必要がなくなります。ローカルストレージから。これにより、さらにスムーズなユーザー エクスペリエンスが提供されます。
Firebase Passwordless Authentication の詳細については、公式ドキュメントを参照してください。