React Firebase 身份验证终极指南

React Firebase 身份验证封面

身份验证是每个应用程序最重要的安全措施之一。

在本文中,我们将讨论身份验证、身份验证类型,比较身份验证和授权,并演示如何将Firebase AuthenticationBack4app AuthenticationReact 应用程序集成。

什么是身份验证?

身份验证是验证某人或某事是否与其声称的身份相符的过程。几乎每个应用程序都使用某种形式的身份验证来确保对应用程序或其数据的访问安全。

最简单的身份验证形式是基于密码的身份验证。这种身份验证系统首先由用户输入用户名和密码。用户输入凭据后,后台会将其与数据库中的记录进行比较,如果凭据正确,则允许用户访问系统。访问权限通常以会话令牌的形式授予。

现代身份验证系统大致是这样的:

现代认证系统流程

认证与授权

认证是验证用户身份的过程,而授权则是验证用户访问权限的过程。

例如,当您登录网上银行系统时,系统将首先通过验证您的登录凭据对您进行身份验证。通过身份验证后,系统将根据您的账户权限确定您有权进行的操作,如是否允许您转账或查看账户对账单。

认证类型

常见的身份验证类型包括

  • 基于密码的身份验证是最常见的身份验证类型。用户通过提供用户名和密码来访问系统或资源。
  • 单点登录(SSO)允许用户使用一套凭证登录多个网站和服务。Google账户就是一个例子。创建 Google 账户后,您就可以访问 Gmail、YouTube、AdSense、Firebase 等。
  • 社交认证是单点登录的一种形式,它使用Google、Facebook 或 Twitter 等社交网络服务中的现有信息来创建账户。
  • 基于令牌的身份验证让用户只需输入一次凭据,就能换取一个由随机字符组成的独特加密字符串。
  • 生物识别身份验证依赖于个人独特的生物特征。生物识别身份验证的类型包括面部识别、指纹扫描仪、扬声器识别和虹膜扫描仪。
  • 基于证书的身份验证使用数字证书验证个人、组织或设备的身份,以建立安全连接,通过互联网交换信息。

如何设置身份验证?

在本部分教程中,我们将首先构建一个虚拟的React身份验证应用程序,然后了解如何将其与Firebase Authentication和 Back4app (Parse) Authentication 集成。

我们将使用以下工具:

先决条件

  • 使用 JavaScript ES6 的经验
  • 充分了解 React(JSX、钩子)
  • 有 React Router 和 Material UI 经验者优先考虑

在深入研究代码之前,我们先来看看这两种身份验证系统的区别。

Firebase 身份验证 vs Back4app 身份验证

FirebaseBack4app都为移动和网络应用程序提供了出色的用户身份验证系统。它们都易于使用,并具有社交登录、电子邮件验证系统、密码重置系统等多种功能。

它们之间最大的区别在于,Back4app 是基于开源软件构建的,而 Firebase 使用的是 Google 的专有软件。此外,Back4app 的价格往往比 Firebase 便宜。

Firebase 身份验证与 Back4app 身份验证的比较

我建议你同时试用这两种身份验证系统,然后再决定你更喜欢哪一种。

如果您想了解 Back4app 和 Firebase 的区别,请参阅Back4app vs Firebase

项目设置

我们已经完成了理论学习。是时候开始编码了!

创建 React 应用程序

让我们先创建一个新的 React 应用程序。

以下步骤需要安装Node.js。如果尚未安装,请从其官方网站下载。

创建 React 应用程序的最简单方法是通过创建 React 应用程序

$ npx create-react-app react-firebase-auth
$ cd react-firebase-auth

这将创建一个名为react-firebase-auth 的新 React 应用程序,并更改工作目录。

接下来,启动项目:

$ npm start

最后,打开http://localhost:3000/查看网络应用。

React 默认项目

Material UI

为了简化用户界面的构建过程,我们将使用Material UI— 一个实现了 Google Material Design 的开源 React 组件库。该组件库包含大量开箱即用的预构建组件。

你可以随意将 Material UI 换成不同的 UI 框架,如React BootstrapAnt Design

要在项目中添加 Material UI,请运行

$ npm install @mui/material @emotion/react @emotion/styled

Material UI 默认使用 Roboto 字体。让我们用

$ npm install @fontsource/roboto

接下来,导航至index.js,并添加以下导入:

// src/index.js

import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';

React 路由器

我们的网络应用程序将有以下端点:

  1. /login— 显示允许用户登录的登录表单。
  2. /register— 显示允许用户注册的注册表单。
  3. /user— 显示用户信息(电子邮件accessToken 等)。

由于我们要构建的是单页面应用程序(Single Page Application,SPA),因此需要一种方法来实现客户端路由。使用 React 的最简单方法就是使用react-router-dom

$ npm install react-router-dom

接下来,在src中为所有视图组件创建一个名为routes的目录。然后在其中添加以下三个文件:

// src/routes/login.jsx

export default function Login() {
  return (
    <h1>Login</h1>
  )
}
// src/routes/register.jsx

export default function Register() {
  return (
    <h1>Register</h1>
  )
}
// src/routes/user.jsx

export default function User() {
  return (
    <h1>User</h1>
  )
}

创建一个BrowserRouter,并在index.js中像这样注册:

// src/index.js

const router = createBrowserRouter([
  {
    path: "/",
    element: <Navigate to="login"/>,
  },
  {
    path: "/login",
    element: <Login/>,
  },
  {
    path: "/register",
    element: <Register/>,
  },
  {
    path: "/user",
    element: <User/>,
  },
]);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <RouterProvider router={router}/>
  </React.StrictMode>
);

不要忘记在文件顶部添加所有必要的导入:

import {createBrowserRouter, Navigate, RouterProvider} from "react-router-dom";
import Login from "./routes/login";
import Register from "./routes/register";
import User from "./routes/user";

要处理 “未找到 (404) “错误,请在src目录中创建一个名为error-page.jsx的新组件,内容如下:

// src/error-page.jsx

import {useRouteError} from "react-router-dom";
import {Container, Typography} from "@mui/material";

export default function ErrorPage() {

  const error = useRouteError();
  console.error(error);

  return (
    <Container maxWidth="xs" sx={{mt: 2}}>
      <Typography variant="h5" component="h1" gutterBottom>
        Oops!
      </Typography>
      <Typography variant="p" component="p" gutterBottom>
        Sorry, an unexpected error has occurred.
      </Typography>
      <Typography variant="p" component="p" gutterBottom>
        <i>{error.statusText || error.message}</i>
      </Typography>
    </Container>
  );
}

然后导航到index.jsx,在索引路由中添加errorElement,如下所示:

// src/index.js

const router = createBrowserRouter([
  {
    path: "/",
    element: <Navigate to="login"/>,
    errorElement: <ErrorPage/>,  // new
  },
  // ...
]);

再次确保添加所需的导入:

import ErrorPage from "./error-page";

此时,您的目录结构应该如下所示:

react-firebase-auth
├── README.md
├── package.json
├── package-lock.json
├── public
│   └── <public files>
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── error-page.jsx
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── reportWebVitals.js
    ├── routes
    │   ├── login.jsx
    │   ├── register.jsx
    │   └── user.jsx
    └── setupTests.js

让我们启动应用程序,测试是否一切正常。运行:

$ npm start

打开您最喜欢的网络浏览器,导航至http://localhost:3000/。这将把您重定向到登录屏幕。然后导航至http://localhost:3000/register,您应该会看到注册屏幕。

形式

我们要做的最后一件事就是实现登录和注册表单。

为此,请导航到路由目录,然后像这样更改login.jsx

// src/routes/login.jsx

import {Alert, Box, Button, Container, Link, TextField, Typography} from "@mui/material";
import {useNavigate} from "react-router-dom";
import {useState} from "react";

export default function Login() {

  const navigate = useNavigate();

  const [error, setError] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const onSubmit = async (event) => {
    event.preventDefault();

    // validate the inputs
    if (!email || !password) {
      setError("Please enter your username and password.");
      return;
    }

    // clear the errors
    setError("");

    // TODO: send the login request
    console.log("Logging in...");
  }

  return (
    <Container maxWidth="xs" sx={{mt: 2}}>
      <Typography variant="h5" component="h1" gutterBottom textAlign="center">
        Login
      </Typography>
      {error && <Alert severity="error" sx={{my: 2}}>{error}</Alert>}
      <Box component="form" onSubmit={onSubmit}>
        <TextField
          label="Email"
          variant="outlined"
          autoComplete="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          sx={{mt: 1}}
          fullWidth
        />
        <TextField
          label="Password"
          variant="outlined"
          type="password"
          autoComplete="new-password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          sx={{mt: 3}}
          fullWidth
        />
        <Button variant="contained" type="submit" sx={{mt: 3}} fullWidth>Login</Button>
        <Box sx={{mt: 2}}>
          Don't have an account yet? <Link href="/register">Register</Link>
        </Box>
      </Box>
    </Container>
  )
}
  1. 我们使用 Material UI 的组件来构建布局,包括表单。
  2. 状态(电子邮件密码)通过 ReactuseState()钩子处理。
  3. 表单提交会调用onSubmit()验证数据并显示潜在错误。

接下来,从 GitHub 获取源代码,替换其他两个路由的内容:

再次运行服务器并导航到网络应用程序。您的视图应该如下所示:

登录/注册/用户验证视图

清理

删除以下由Create React App创建但不再需要的文件:

  • src/App.css
  • src/App.js
  • src/App.test.js
  • src/logo.svg

确保从index.js等文件中移除任何可能的导入。

很好,我们的虚拟身份验证网络应用程序现在完成了。在接下来的章节中,我们将通过添加 Firebase 身份验证和 Back4app 身份验证对其进行升级。

back4app-react-firebase-auth软件仓库获取这部分内容的源代码。

React Firebase 身份验证

在本节教程中,我们将了解如何将 Firebase 身份验证与 React 项目集成。首先,我们将使用在 “项目设置 “部分创建的 React 应用程序

在学习本教程的过程中,请使用自己的 React 项目来检查您的理解。

创建项目和应用程序

以下步骤需要您拥有一个Firebase 账户。如果您还没有账户,请使用 Google 账户注册。

要使用 Firebase,我们首先需要创建一个项目。要创建项目,请登录Firebase 控制台并点击 “创建项目”:

Firebase 控制台

给它起一个自定义名称,我的名称是react-firebase-auth

接受所有条款和条件,然后按 “继续”。

Firebase 会花一些时间准备项目所需的一切。一旦完成,你将被重定向到 Firebase 项目控制面板。

接下来,创建一个新的 Firebase 应用程序。选择 “Web”,因为我们使用 React 作为前端:

Firebase 创建网络应用程序

给它起一个自定义名称–或者重复使用你的项目名称。您不必启用 Firebase Hosting,因为我们不会使用它。

接下来,点击 “注册应用程序”:

Firebase Web 应用程序设置

然后选择 “npm”,并记下你的 Firebase SDK 配置。最后,点击 “继续到控制台 “按钮:

创建 Firebase 应用程序 SDK

启用身份验证

在深入学习代码之前,我们必须启用身份验证。

在 Firebase 控制台左侧选择 “构建”,然后选择 “身份验证”。重定向后,点击 “开始”:

Firebase 身份验证设置

Firebase 提供多种登录方法。在本教程中,我们将演示如何使用电子邮件和密码验证,因此这是你唯一需要启用的方法:

Firebase 启用身份验证 (2)

Firebase SDK

要在 React 项目中使用 Firebase,首先必须安装其软件开发工具包(SDK)。

通过 npm 安装:

$ npm install firebase

接下来,在src文件夹中新建一个名为firebase.js的文件,内容如下:

// src/firebase.js

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

// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
  apiKey: "AIzaSyC4m7VHfM8hy_VUUAlpFCSK3AfrRX4bkQ0",
  authDomain: "react-firebase-auth-d4e6b.firebaseapp.com",
  projectId: "react-firebase-auth-d4e6b",
  storageBucket: "react-firebase-auth-d4e6b.appspot.com",
  messagingSenderId: "1084832623816",
  appId: "1:1084832623816:web:a526bb5b9beff5e26e89fd",
  measurementId: "G-1DXS0RGXPT"
};

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

确保将firebaseConfig替换为上一步中的配置。

Firebase SDK 提供不同的验证方法,例如

  1. createUserWithEmailAndPassword(email: string, password: string)
  2. signInWithEmailAndPassword(email: string, password: string)

要使用这些方法,让我们在firebase.js文件底部创建两个封装函数:

// firebase.js

// ...

export const createUser = async (email, password) => {
  return createUserWithEmailAndPassword(getAuth(app), email, password);
}

export const signInUser = async (email, password) => {
  return signInWithEmailAndPassword(getAuth(app), email, password);
}

别忘了添加导入:

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

这些功能不言自明:

  1. createUser创建 Firebase 用户(并返回包含用户信息的响应)
  2. signInUser登录现有 Firebase 用户(并返回包含用户信息的响应)

会话持久性

Firebase 不会像 Parse 那样在客户端设备上进行会话持久化处理。

因此,我们必须使用Window.sessionStorage。当用户登录时,我们必须存储他们的访问令牌,并在每次进行验证请求时检索它。

为了让事情变得简单一些,我们将创建一个辅助类。

src目录中新建一个名为session.js的文件,内容如下:

// src/storage/session.js

export const startSession = (user) => {
  sessionStorage.setItem("email", user.email);
  sessionStorage.setItem("accessToken", user.accessToken);
}

export const getSession = () => {
  return {
    email: sessionStorage.getItem("email"),
    accessToken: sessionStorage.getItem("accessToken"),
  }
}

export const endSession = () => {
  sessionStorage.clear();
}

export const isLoggedIn = () => {
  return getSession().accessToken;
}

意见

我们要做的最后一件事就是修改视图,以便利用我们创建的函数,并通过session.js 中的辅助函数设置会话。

打开login.jsx,像这样更改onSubmit()TODO:

// src/routes/login.jsx

import {signInUser} from "../firebase";
import {startSession} from "../session";

const onSubmit = async (event) => {

  // ...

  try {
    let loginResponse = await signInUser(email, password);
    startSession(loginResponse.user);
    navigate("/user");
  } catch (error) {
    console.error(error.message);
    setError(error.message);
  }
}

这段代码要么登录用户并导航到/user,要么显示错误。

接下来,像这样修改register.jsx onSubmit()TODO:

// src/routes/register.jsx

import {createUser} from "../firebase";
import {startSession} from "../session";

const onSubmit = async (event) => {

  // ...

  try {
    let registerResponse = await createUser(email, password);
    startSession(registerResponse.user);
    navigate("/user");
  } catch (error) {
    console.error(error.message);
    setError(error.message);
  }
}

该代码要么创建 Firebase 用户,要么显示错误。可能出现的错误包括

  1. 用户名已被注册。
  2. 密码不够强。

最后,修改user.jsx,使用useEffect()钩子获取用户数据,并让onLogout()销毁会话:

// src/routes/user.jsx

import {endSession, getSession, isLoggedIn} from "../session";

useEffect(() => {
  if (!isLoggedIn()) {
    navigate("/login");
  }

  let session = getSession();
  setEmail(session.email);

  console.log("Your access token is: " + session.accessToken);
}, [navigate]);

const onLogout = () => {
  endSession();
  navigate("/login");
}

测试

让我们测试一下网络应用程序,看看是否一切正常。

使用npm start 启动开发服务器,打开您喜欢的网络浏览器,并导航至http://localhost:3000/register。输入电子邮件、密码,然后点击 “注册”:

Firebase 身份验证测试

注册后,您将被重定向到/user,在那里您可以看到您的账户信息。

要查看访问令牌,请打开浏览器的开发者控制台:

Your access token is: 819423a698f9ea9ba3577f20993cb0da98a79ea22ce5d6550b65b69fb36fd438

最后,导航到 Firebase 项目仪表板,检查是否创建了新用户:

Firebase 身份验证用户

back4app-react-firebase-authrepo 中获取此方法的最终源代码。

React Back4app 身份验证

在本节教程中,我们将了解如何将 Back4app 身份验证与 React 项目集成。首先,我们将使用在 “项目设置 “部分创建的 React 应用程序

在学习本教程的过程中,请使用自己的 React 项目来检查您的理解。

创建应用程序

以下步骤需要您拥有 Back4app 帐户。如果您已经拥有该账户,请登录,否则请注册免费账户

要使用 Back4app,我们首先需要创建一个应用程序。登录仪表板后,您将看到应用程序列表。点击 “创建新应用程序 “创建新应用程序。

Back4app 创建应用程序

自定义名称,选择数据库,然后点击 “继续”。

Back4app 会花一些时间准备应用程序所需的一切,如数据库、应用层、扩展、备份和安全。

应用程序准备就绪后,您将被重定向到应用程序的控制面板。

Back4app 应用程序控制面板

应用程序密钥

要将您的 React 项目与 Back4app 连接,您需要获取应用程序密钥。要获取应用密钥,请选择侧边栏上的 “应用设置”,然后选择 “安全与密钥”。

注意 “应用程序 ID “和 “JavaScript 密钥”。

Back4app 安全性和密钥

Parse SDK

您可能已经知道,Back4app 是基于 Parse 开发的。Parse 是一个用于构建应用程序后端的开源框架。它可以帮助开发人员加快应用程序的开发速度,减少构建应用程序所需的总工作量。

要了解有关 Parse 的更多信息,请参阅《什么是 Parse?

要设置 Back4app 身份验证,我们首先需要安装 Parse SDK。通过 npm 安装:

$ npm install parse

接下来,在src文件夹中新建一个名为parse.js的文件,内容如下:

// src/parse.js

import Parse from "parse/dist/parse";

// Initialize Parse
const PARSE_APPLICATION_ID = '<your_parse_application_id>';
const PARSE_HOST_URL = 'https://parseapi.back4app.com/';
const PARSE_JAVASCRIPT_KEY = '<your_parse_javascript_key>';
Parse.initialize(PARSE_APPLICATION_ID, PARSE_JAVASCRIPT_KEY);
Parse.serverURL = PARSE_HOST_URL;

确保将PARSE_APPLICATION_IDPARSE_JAVASCRIPT_KEY替换为上一步中的键值。

Parse 提供了一个名为Parse.User的专门类,它能自动处理用户账户管理所需的大部分功能。Parse.UserParseObject的一个子类,它提供了额外的辅助方法,如signUp ()current()getUsername()等。

此外,Parse SDK 还能处理本地存储会话。例如,Parse.User.logIn()会将用户信息存储在本地存储中,而Parse.User.signOut()则会清除本地存储。

让我们添加几个封装函数,进一步简化 Parse 身份验证系统的工作。

parse.js 的底部添加以下内容:

// src/parse.js

// ...

export const doUserRegistration = async (username, password) => {
  return Parse.User.signUp(username, password);
};

export const doUserLogIn = async (username, password) => {
  return Parse.User.logIn(username, password);
};

export const isLoggedIn = async () => {
  return Parse.User.current() != null;
}

export const getUser = async () => {
  return Parse.User.current();
}

export const logOut = async () => {
  return Parse.User.logOut();
}
  1. doUserRegistration()创建 Parse 用户(使用电子邮件和密码)
  2. doUserLogIn()尝试使用提供的凭据登录用户
  3. isLoggedIn()检查localStorage是否包含会话信息
  4. getUser()会从本地存储返回已登录用户的信息
  5. logOut()清除本地存储,从而注销用户

所有函数都是异步的,并返回承诺。

意见

让我们利用上一步创建的函数。

打开login.jsx,像这样更改onSubmit()TODO:

// src/routes/login.jsx

import {doUserLogIn} from "../parse";

const onSubmit = async (event) => {

  // ...

  try {
    let user = await doUserLogIn(email, password);
    navigate("/user");
  } catch (error) {
    console.error(error.message);
    setError(error.message);
  }
}

这段代码要么登录用户并导航到/user,要么显示错误。

接下来,像这样修改register.jsx onSubmit()TODO:

// src/routes/register.jsx

import {doUserRegistration} from "../parse";

const onSubmit = async (event) => {

  // ...

  let username = email.split("@")[0];
  try {
    let user = await doUserRegistration(username, password);
    user.setEmail(email).save();
    navigate("/user");
  } catch (error) {
    console.error(error.message);
    setError(error.message);
  }
}

请记住,由于我们使用的是电子邮件/密码注册表单,因此必须从电子邮件中提取用户的用户名。用户名是@ 前面的部分。

更好的解决方案是创建一个用户名/密码注册表。

该代码要么创建 Parse 用户,要么显示错误。可能出现的错误包括

  1. 用户名已被注册。
  2. 密码不够强。

最后,修改user.jsx,使用useEffect()钩子获取用户数据,并让onLogout()调用注销函数:

// src/routes/user.jsx

import {getUser, isLoggedIn, logOut} from "../parse";

useEffect(() => {
  (async () => {
    let loggedIn = await isLoggedIn();
    if (!loggedIn) {
      navigate("/login");
    }

    let user = await getUser();
    setEmail(user.getEmail());

    console.log("Your session token is: " + user.getSessionToken());
  })();
}, [navigate]);

const onLogout = async () => {
  await logOut();
  navigate("/login");
}

很好,就是这样!

测试

让我们确保我们的身份验证系统按预期运行。

使用npm start 启动开发服务器,打开您喜欢的网络浏览器,并导航至http://localhost:3000/register。输入电子邮件、密码,然后点击 “注册”:

Back4app 身份验证测试

注册后,您将被重定向到/user,在那里您可以看到您的账户信息。

要查看会话令牌,请打开浏览器的开发者控制台:

Your session token is: r:90343c307e7bb088e60c348acd8090d1

最后,导航至 Back4app 应用程序控制面板,确保已创建用户:

Back4app 数据库用户

back4app-react-firebase-authrepo 中获取此方法的最终源代码。

结论

身份验证和授权是现代应用程序最重要的安全措施。身份验证是验证用户身份的过程,而授权则是验证用户访问权限的过程。

Firebase 和 Back4app 都提供了出色的用户身份验证系统。它们各有利弊,在启动项目时应加以考虑。

更多阅读

常见问题

什麼是身份驗證?

身份驗證是驗證使用者或裝置身份的過程。這是一種安全措施,旨在確保只有授權的使用者或裝置能夠存取系統、網路或資源。

身份驗證的類型有哪些?

– 使用者名稱和密碼
– 單一登入(SSO)
– 社群身份驗證
– 基於令牌的身份驗證
– 生物識別身份驗證
– 憑證式身份驗證

如何使用 Firebase 設定身份驗證?

1. 使用您的 Google 帳戶登入 Firebase
2. 建立 Firebase 專案和應用程式
3. 啟用 Firebase 身份驗證功能
4. 安裝 Firebase SDK 並初始化
5. 在您的視圖中使用 Firebase SDK 的身份驗證功能
6. 使用 Window.sessionStorage 來處理工作階段

如何使用 Back4app 設定身份驗證?

1. 在 Back4app 建立帳戶
2. 建立 Back4app 應用程式
3. 安裝 Parse SDK 並初始化
4. 在您的視圖中使用 ParseJS 的身份驗證功能


Leave a reply

Your email address will not be published.