React 中使用 Firebase 身份验证

Firebase 提供身份验证服务,可以让您的应用轻松集成注册和登录功能。 您可以使用电子邮件、密码、电话号码以及 Google 和 Facebook 等身份提供商。

React 中使用 Firebase 身份验证

Firebase 提供身份验证服务,可以让您的应用轻松集成注册和登录功能。 您可以使用电子邮件、密码、电话号码以及 Google 和 Facebook 等身份提供商。

在本教程中,您将学习如何在 React 中使用 Firebase 身份验证来使用电子邮件和密码对用户进行身份验证。 您将把收集到的用户数据存储在 Firestore 中,这是一个同样来自 Firebase 的 NoSQL 云数据库。

请注意,本教程使用 Firebase v9 和 React Router v6。

创建 Firebase 应用程序

要将您的应用程序连接到 Firebase,请向 Firebase 注册您的应用程序以获取配置对象。 这是您将用于在 React 应用程序中初始化 Firebase 的内容。

要创建 Firebase 应用程序,请按照以下步骤操作。

  • 转到 Firebase 控制台并单击创建项目。
  • 为您的项目命名,然后单击创建以开始该过程。
  • 单击项目概览页面上的 Web 图标 (/>) 以注册应用程序。
  • 为您的应用程序命名,然后单击注册应用程序。 您不需要启用 Firebase 托管。
  • 复制添加 Firebase SDK 下的配置对象。

创建反应应用程序

使用 create-react-app 搭建一个 React 应用程序。

npx create-react-app react-auth-firebase

导航到该文件夹并启动应用程序。

cd react-auth-firebase
npm run start

使用 Firebase 函数对用户进行身份验证

在使用 Firebase 之前,先安装它。

npm i firebase

创建一个新文件 firebase.js,并初始化 Firebase。

import { initializeApp } from "firebase/app";

const firebaseConfig = {
  apiKey: <api_key>,
  authDomain:<auth_domain> ,
  projectId: <project_id>,
  storageBucket: <storage_bucket>,
  messagingSenderId: <messaging_sender_id>,
  appId: <app_id>
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);

使用您在注册应用程序时复制的配置对象。

接下来导入您将使用的 Firebase 模块。

import {
  getAuth,
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  signOut,
} from "firebase/auth";

import { getFirestore, addDoc, collection } from "firebase/firestore";

const db = getFirestore();

const auth = getAuth();

要对用户进行身份验证,您需要创建三个函数:signUp、signIn 和 signOut。

signUp 函数将电子邮件和密码传递给 createUserWithEmailAndPassword 以注册新用户。 createUserWithEmailAndPassword 返回您将用于在数据库中创建新用户记录的用户数据。

const signUp = async (email, password) => {
  try {
    const userCredential = await createUserWithEmailAndPassword(
      auth,
      email,
      password
    );
    const user = userCredential.user;
    await addDoc(collection(db, "users"), {
      uid: user.uid,
      email: user.email,
    });
    return true
  } catch (error) {
    return {error: error.message}
  }
};

请注意,您不会在注册前检查电子邮件是否已被使用,因为 Firebase 会为您处理。

接下来,在 signIn 函数中将电子邮件和密码传递给 signInWithEmailAndPassword 函数以登录注册用户。

const signIn = async (email, password) => {
  try {
    const userCredential = await signInWithEmailAndPassword(
      auth,
      email,
      password
    );
    const user = userCredential.user;
    return true
  } catch (error) {
    return {error: error.message}
  }
};

如果成功,则 signUp 和 signOut 函数都返回 true,如果发生错误,则返回一条错误消息。

signOut 函数非常简单。 它从 Firebase 调用 signOut() 函数。

const signOut = async() => {
  try {
    await signOut(auth)
    return true
  } catch (error) {
    return false
  }
};

创建 React 表单

登录和注册表单将从用户那里收集电子邮件和密码。

创建一个新组件 Signup.js 并添加以下内容。

import { useState } from "react";
import { Link } from "react-router-dom";
import { signUp } from "./firebase";

const Signup = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, seterror] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (password !== password2) {
      seterror("Passwords do not match");
    } else {
      setEmail("");
      setPassword("");
      const res = await signUp(email, password);
      if (res.error) seterror(res.error)
    }
  };

  return (
    <>
      <h2>Sign Up</h2>
      <div>
        {error ? <div>{error}</div> : null}
        <form onSubmit={handleSubmit}>
          <input
            type="email"
            name="email"
            value={email}
            placeholder="Your Email"
            required
            onChange={(e) => setEmail(e.target.value)}
          />
          <input
            type="password"
            name="password"
            value={password}
            placeholder="Your Password"
            required
            onChange={(e) => setPassword(e.target.value)}
          />
          <button type="submit">Submit</button>
        </form>
        <p>
          already registered? <Link to="/login">Login</Link>
        </p>
      </div>
    </>
  );
};

export default Signup;

在这里,您将创建一个注册表单并使用状态跟踪电子邮件和密码。 提交表单后,onSubmit 事件会触发 handleSubmit() 函数,该函数从 firebase.js 调用 signUp() 函数。 如果函数返回错误,则更新错误状态并显示错误消息。

对于登录表单,创建 Signin.js 并添加以下内容。

import { useState } from "react";
import { signIn } from "./firebase";

const Login = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, seterror] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    setEmail("");
    setPassword("");
    const res = await signIn(email, password);
    if (res.error) seterror(res.error);
  };

  return (
    <>
      {error ? <div>{error}</div> : null}
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          name="email"
          value={email}
          placeholder="Your Email"
          onChange={(e) => setEmail(e.target.value)}
        />
        <input
          type="password"
          name="password"
          value={password}
          placeholder="Your Password"
          onChange={(e) => setPassword(e.target.value)}
        />
        <input type="submit" value="submit" />
      </form>
    </>
  );
};

export default Login;

登录表单与注册页面非常相似,只是提交调用了 signIn() 函数。

最后,创建个人资料页面。 这是应用程序在成功验证后将用户重定向到的页面。

创建 Profile.js 并添加以下内容。

import { signOut } from "./firebase";

const Profile = () => {
  const handleLogout = async () => {
   await signOut();
  };
  return (
    <>
      <h1>Profile</h1>
 <button onClick={handleLogout}>Logout</button>
    </>
  );
};

export default Profile;

在此组件中,您有配置文件标题和注销按钮。 按钮上的 onClick 处理程序触发注销用户的 handleLogout 函数。

创建身份验证路由

要将您创建的页面提供给浏览器,请设置 react-router-dom。

安装 react-router-dom:

npm i react-router-dom

在 index.js 中,配置 react-router-dom:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Routes, Route } from "react-router-dom";

import App from "./App";
import Login from "./Login";
import Profile from "./Profile";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <AuthProvider>
        <Routes>
          <Route path="/" element={<App />} />
          <Route path="login" element={<Login />} />
          <Route path="profile" element={<Profile />} />
        </Routes>
      </AuthProvider>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

到目前为止,应用程序可以注册用户、注册和注销。 那么如何知道用户是否登录呢?

在本教程的下一部分中,您将了解如何使用 React 上下文来跟踪应用程序中用户的身份验证状态。

使用 React Context API 管理身份验证

React Context 是一种状态管理工具,可简化跨应用程序的数据共享。 它是 prop 的更好替代方案,在 prop 中,数据从父级向下传递到子级,直到到达需要它的组件。

创建身份验证上下文

在 src 文件夹中,添加 AuthContext.js 文件并创建和导出 AuthContext。

import { createContext } from "react";
const AuthContext = createContext();
export default AuthContext;

接下来,在 AuthProvider.js 中创建提供者。 它将允许组件使用 AuthContext。

import { useState, useEffect } from 'react';
import { getAuth, onAuthStateChanged } from "firebase/auth";

import AuthContext from './AuthContext';
const auth = getAuth();

export const AuthProvider = ({ children }) => {
    const [user, setUser] = useState(null);

    useEffect(() => {
        onAuthStateChanged(auth,(user) => {
            setUser(user)
        })
    }, []);

    return (
      <AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>
    );
  };

在这里,您使用 Firebase 的 onAuthStateChanged() 方法获取用户值。 如果此方法对用户进行身份验证,则返回一个用户对象;如果不能,则返回 null。 通过使用 useEffect() 挂钩,每次身份验证状态更改时都会更新用户值。

在 index.js 中,使用 AuthProvider 包装路由以确保所有组件都在上下文中访问用户:

import { AuthProvider } from "./AuthProvider";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <AuthProvider>
        <Routes>
          <Route path="/" element={<App />} />
          <Route path="login" element={<Login />} />
          <Route path="profile" element={<Profile />} />
        </Routes>
      </AuthProvider>
    </BrowserRouter>
    ,
  </React.StrictMode>,
  document.getElementById("root")
);

创建受保护的路由

为了保护敏感路由,请检查试图导航到受保护页面(如个人资料页面)的用户的身份验证状态。

如果用户未通过身份验证,请修改 Profile.js 以重定向用户。

import { useContext } from "react";
import { useNavigate, Navigate } from "react-router-dom";

import AuthContext from "./AuthContext";
import { signOut } from "./firebase";

const Profile = () => {
  const { user } = useContext(AuthContext);
  const navigate = useNavigate();
  const handleLogout = async () => {
   await signOut();
  };

  if (!user) {
    return <Navigate replace to="/login" />;
  }
  
  return (
    <>
      <h1>Profile</h1>
 <button onClick={handleLogout}>Logout</button>
    </>
  );
};

export default Profile;

如果用户未通过身份验证,应用程序会通过将用户重定向到登录页面来有条件地呈现个人资料页面。

进一步使用 Firebase 身份验证

在本教程中,您使用 Firebase 通过用户的电子邮件和密码对用户进行身份验证。 您还在 Firestore 中创建了用户记录。 Firebase 提供与 Google、Facebook 和 Twitter 等身份验证提供商合作的功能。