介绍 本指南是 的补充。在该指南的介绍中,我注意到 Firebase 提供了除基本电子邮件/密码身份验证之外的其他身份验证方案。这些替代方案之一是 。 如何使用 React Web 应用程序设置 Firebase 身份验证 无密码身份验证 在构建应用程序时,无密码身份验证是一个有吸引力的选择。它简化了用户体验,因为您的用户无需记住他们的密码,因此也不必担心丢失密码。它还简化了开发体验,因为无需设计任何密码捕获或管理逻辑。 在本指南中,您将构建一个简单的登录/确认/个人资料/注销工作流程来实现 Firebase 的无密码身份验证。 在你开始之前 Google 设置了各种 Firebase 身份验证 。如果您使用免费的 计划,请注意,您每天 只能发送 5 封登录链接电子邮件。虽然 Spark 计划可能足以满足测试目的,但您需要升级到即用即付 计划才能超过此限制。 限制 Spark 最多 Blaze 先决条件 在本指南中,我将参考 指南作为 ,并将关联的项目作为 。 如何使用 React Web 应用程序设置 Firebase 身份验证 先决条件指南 先决项目 要完成本指南,您需要: 已完成先决条件指南,包括所有先决条件。 第 1 步 - 在您的 Firebase 项目中启用无密码身份验证 在先决条件指南中,您创建了一个用于基本电子邮件/密码身份验证的新 Firebase 项目。现在,您将为同一项目启用无密码身份验证。登录您的 并点击 。 Firebase 帐户 Go to Console 单击 Firebase 项目仪表板上列出的身份验证项目。本指南使用项目名称 。 my-auth-test 单击左侧面板菜单中的 。 身份验证 单击主窗口中的 选项卡。 登录方法 根据您在先决条件指南中的工作, 表应该已在 列下显示 ,状态为 。单击铅笔图标打开 提供商的配置面板。 登录提供程序 提供程序 电子邮件/密码 Enabled 电子邮件/密码 单击开关以启用 。 电子邮件链接(无密码登录) 单击 。 “保存” 您的 Firebase 项目现已配置为支持无密码身份验证。 第 2 步 - 创建一个新的 React 项目并安装包 步骤 2a - 创建一个新的 React 项目 使用您所需的应用程序名称创建一个新的 React 项目。本指南使用 。 passwordless-auth npx create-react-app passwordless-auth 步骤 2b - 安装软件包 本指南需要安装 3 个 Node.js 包: :Firebase SDK。 Firebase :用于路由。 React Router DOM :用于样式。 Bootstrap 通过 安装上述三个软件包: npm npm install firebase npm install react-router-dom npm install bootstrap 第 3 步 - 从先决项目复制 firebase.js 在必备项目中,您创建了一个 文件,该文件使用 Firebase 项目配置数据来创建 Firebase 身份验证服务的实例。您的 文件应具有以下结构以及 Firebase 项目配置值: firebase.js firebase.js 您的 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 } 将 复制到新的 React 项目文件夹。 firebase.js 如果您需要查看 Firebase 项目配置,请单击左侧面板菜单中 旁边的齿轮图标。应已选择 选项卡。向下滚动到包含 面板的 部分。 面板中的 选项应该已被选择。您的项目配置值将在显示的代码块中列出。 “项目概述” “常规” Web 应用程序 “您的应用程序” Web 应用程序 npm 第 4 步 - 构建 React 应用程序 步骤 4a - React 应用程序组件概述 React 应用程序将由 5 个组件组成: 、 、 、 和 。 App Layout Login Confirm Profile 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 步骤 4b - 清理 React 项目模板并从必备项目中复制文件 您可以按照先决条件指南的步骤 5b.1 中所述从 React 项目模板中删除相同的文件。从 React 项目中删除以下文件: reportWebVitals.js setupTests.js logo.svg index.css App.css App.test.js 将 从必备项目复制到新项目文件夹。本指南使用相同的文件。如果您需要重建 ,请参阅先决条件指南的步骤 5b.2 或复制下面的代码块。 index.js index.js 将 从必备项目复制到新项目文件夹。本指南使用相同的文件。如果您需要重建 ,请参阅先决条件指南的步骤 5d 或复制下面的代码块。或者,您可以将 的 标记中的项目文本更新为 或任何您喜欢的标题。 Layout.jsx Layout.jsx 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 步骤 4c - 构建 App.js 文件与必备项目中的文件基本相同,仅更改了两行。为了便于构建文件,请将 从必备项目复制到新项目文件夹。 App.js 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 步骤 4d - 构建 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 = "name@example.com" 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 捕获用户的电子邮件地址后, 表单会通过 Firebase 的 方法向他/她的地址发送一封包含登录链接的电子邮件。如果成功,用户会收到电子邮件已发送的通知。请注意, 对象作为参数传递给 方法,并包含用户单击通过电子邮件发送的登录链接时将路由到的 URL。在本例中,URL 映射到 中指定的 路由。 Login.jsx sendSignInLinkToEmail actionCodeSettings sendSignInLinkToEmail App.js /confirm 步骤 4e - 构建 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 = "name@example.com" 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 方法首先检查用户使用的登录链接是否有效。如果是,则调用 方法来登录用户。重申一下,传递给 方法的 值必须与用户在登录表单中使用的电子邮件地址匹配。请注意,如果用户是新用户(即,这是他/她第一次登录),Firebase 将自动在 Firebase 身份验证存储中创建该用户。这是无密码身份验证提供的简化体验的另一个示例:自动处理新用户的帐户创建。 isSignInWithEmailLink signInWithEmailLink signInWithEmailLink email 步骤 4f - 构建 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 第 5 步 - 测试应用程序 启动 React 应用程序: npm start 如果您的浏览器没有自动启动,请在浏览器中导航至 。您应该看到 表单。 locahost:3000 Login 输入您要用于登录的电子邮件,然后单击 。如果提交成功,将显示一条通知,表明带有登录链接的电子邮件已发送到您的电子邮件地址。 “提交” 登录您的电子邮件帐户并查找 Firebase 登录链接电子邮件。它的主题行应类似于 ,其中 13 位数字序列代表 Firebase 项目的 (请参阅本指南的步骤 3)。在下面的 部分中,我将解释如何修改 Firebase 项目名称以在登录链接电子邮件中显示“用户友好”的名称。现在,打开登录链接电子邮件并单击登录链接。您将被转到 表单。 Sign in to project-1078604952662 messagingSenderId 可选 Confirm 输入您在 表单上登录时使用的电子邮件地址。单击 。如果确认成功,您将被引导至 页面。 Confirm “确认” Profile 单击 页面上的 按钮以注销。如果注销成功,您将返回到 表单。 Profile “注销” Login 上述步骤捕获了应用程序的工作流程。 可选:修改您的项目名称 您可以更改项目名称,以便 Firebase 发送的登录链接电子邮件显示“用户友好”的名称,而不是诸如 之类的名称。登录您的 并点击 。 project-1078604952662 Firebase 帐户 Go to Console 单击 Firebase 项目仪表板上列出的身份验证项目。 单击左侧面板菜单中 旁边的齿轮图标。应已选择 选项卡。 “项目概述” “常规” 向下滚动到 部分中的 选项。 “您的项目” “面向公众的名称” 单击铅笔图标并根据需要修改项目名称。 单击 。您的登录链接电子邮件现在将显示更新的项目名称。 “保存” 结论和后续步骤 无密码身份验证似乎是应用程序开发人员中越来越流行的选择,这是可以理解的。除了无需管理密码的明显优势之外,还不需要电子邮件验证,因为发送登录链接的过程本身就是一种验证。 与先决项目一样,这里的实施是基础的。您可以考虑简单的增强功能,例如: 将特定电子邮件地址域(即常见的垃圾邮件域)阻止/列入黑名单。 本地存储用户在 页面输入的电子邮件地址,并在 页面检查该电子邮件地址是否存在。通过这种方法,如果用户在访问 页面的同一设备上单击登录链接,则他/她无需在 页面上再次输入他/她的电子邮件地址,因为该地址将被恢复来自本地存储。这提供了更加顺畅的用户体验。 Login Confirm Login Confirm 您可以通过 了解有关 Firebase 无密码身份验证的更多信息。 官方文档