为 React 应用程序添加用户身份验证功能

Add User Authentication To Your React App
Add User Authentication To Your React App

在构建网络应用程序时,用户身份验证是添加到应用程序中的必要功能。用户身份验证允许通过验证的用户访问应用程序中的可用功能,并拒绝未经验证的用户访问。

在 React 应用程序中集成用户身份验证并非易事,而且非常耗时,因为这涉及到多个复杂的过程,例如散列密码、生成和管理身份验证令牌等等。

不过,有了 Back4App 这样的平台,在 React 应用程序中集成用户身份验证就变得简单易行了。在本文中,您将了解如何使用 Back4App 在 React 应用程序中添加用户身份验证。

了解用户身份验证

用户身份验证是确定试图访问应用程序的人的身份的过程。

它要求试图访问应用程序的人提供可验证的凭证,凭证的形式可以是用户名和密码、生物识别数据、访问密钥/令牌等。

如果您的身份验证机制认为凭据有效,就会允许用户访问您的应用程序,否则就会拒绝身份验证请求并给出相应的错误信息。

常见身份验证方法

常见的身份验证方法包括以下几种:

  • 用户名和密码:这种身份验证方法要求用户提供有效的用户名和密码,以验证其身份。用户提供用户名和密码后,这种身份验证机制会将其与数据库中存储的数据进行比较,只有在两者匹配时才会批准身份验证请求。
  • 多因素身份验证(MFA):多因素身份验证是指结合多种身份验证机制对用户进行身份验证。在使用 MFA 的身份验证系统中,用户需要多次验证自己的身份。例如,用户在使用用户名和密码验证身份后,可能需要输入验证码。
  • 生物识别身份验证:生物识别身份验证是指依靠生物特征(如脸部、虹膜图案、指纹或声音识别)来验证用户身份的身份验证机制。
  • OAuthOAuth 是一种身份验证协议,允许用户通过授权应用程序访问其首选的 OAuth 提供商(如 Facebook 或 X(前 Twitter))来验证其身份。当用户尝试使用 OAuth 进行身份验证时,他们将被重定向到 OAuth 提供商的登录屏幕,以验证其身份。
  • JSON 网络令牌(JWT):JWT 是一种可移植、URI 安全的紧凑型令牌格式,通常用于在不同方之间安全地传输身份验证和授权详细信息。使用 JWT 进行身份验证时,用户需要在请求中发送 JWT 访问令牌,以验证自己的身份。

使用 Back4app 为应用程序添加用户身份验证功能

Back4app是一个云平台,可提供多种服务,包括 “后台即服务”(BaaS)功能。Back4app 的 BaaS 选项提供各种功能,包括用户身份验证。

使用 Back4app 实施用户身份验证需要几个步骤。在本教程中,您将使用 React 构建一个简单的银行管理应用程序。

该应用程序将集成 Back4app 身份验证功能,允许您创建账户、登录账户、访问当前登录信息和注销。

创建 React 应用程序

要创建一个新的 React 应用程序,首先要使用 Vite 搭建一个新的 React 应用程序脚手架。Vite 是一款网络开发构建工具,可提供更快、更高效的开发体验。

在终端运行以下命令,为新的 React 应用程序搭建脚手架:

npm init vite

运行上述命令后,屏幕上将显示一系列提示,要求您指定应用程序的名称、所选框架以及要使用的语言变量。

就像这样

使用 Vite 创建 React 应用程序

在上图中,应用程序的名称是 react-authentication-app,选择的框架是 React,语言变量是 JavaScript。

接下来,将当前目录更改为应用程序目录,并运行以下命令安装必要的依赖项:

cd react-authentication-app && npm install

接下来,运行下面的命令在应用程序中安装 React Router:

npm install react-router-dom

接下来,在 IDE(集成开发环境)上打开 React 应用程序,然后用下面的代码块替换内容,修改main.jsx文件。

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { BrowserRouter } from 'react-router-dom'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
)

该代码块从react-router-dom包中导入BrowserRouter组件,并封装App组件。

这样就可以在整个应用程序中启用路由。在应用程序组件中,定义应用程序中的不同路由。

就像这样

import { Route, Routes } from "react-router-dom";
import Signup from "./pages/Signup";
import Login from "./pages/Login";
import Home from "./pages/Home";

function App() {

  return (
    <>
      <Routes>
        <Route path="/home" element={<Home />} />
        <Route path="" element={<Signup />}/>
        <Route path="/login" element={<Login />}/>
      </Routes>
    </>
  )
}

export default App

上面的代码块定义了三个独立的路径,允许用户根据 URL 路径在注册、登录和主页之间导航。

现在,在应用程序的src目录中创建一个组件文件夹。在该文件夹中,创建Authnavbar.jsx文件。该组件将包含一个导航栏,显示在注册和登录页面上。

Authnavbar组件中编写以下代码:

import React from "react";
import { Link } from "react-router-dom";

function Authnavbar(props) {
  return (
    <nav>
      <h3>Banka</h3>
      {props.type === "signup" ? (
        <div>
          If you already have an account{""}
          <Link to="/login" className="link">
            Log in
          </Link>
        </div>
      ) : props.type === "login"? (
        <div>
          If you don't have an account{""}
          <Link to="/" className="link">
            Sign Up
          </Link>
        </div>
      ) : null}
    </nav>
  );
}

export default Authnavbar;

上面的代码块根据类型道具的值创建了一个有条件呈现的导航栏,允许用户在应用程序中的注册页面和登录页面之间导航。

接下来,在应用程序的src目录中生成一个页面文件夹。在该文件夹中创建三个组件:Home.jsxSign-up.jsxLogin.jsx。这些文件将作为主页、注册页面和登录页面。

注册页面将包含一个表单,用户可在此输入用户名、电子邮件和密码等详细信息。

例如

import React from "react";
import Authnavbar from "../components/Authnavbar";

function Signup() {
  const [formData, setFormData] = React.useState({
    username: "",
    email: "",
    password: "",
  });

  const handleChange = (event) => {
    setFormData((prevState) => ({
      ...prevState,
      [event.target.name]: event.target.value,
    }));
  };

  return (
    <>
      <Authnavbar type= "sign-up"/>
      <form>
        <input
          type= "text"
          name= "username"
          placeholder= "Username..."
          onChange={handleChange}
          value={formData.username}
        />
        <input
          type= "email"
          name= "email"
          placeholder= "Email..."
          onChange={handleChange}
          value={formData.email}
        />
        <input
          type= "password"
          name= "password"
          placeholder= "Password..."
          onChange={handleChange}
          value={formData.password}
        />
        <div>
          <button>Sign Up</button>
        </div>
      </form>
    </>
  );
}

export default Sign-up;

该代码块表示一个注册页面。它包含一个带有输入字段的表单,其中包括用户的用户名、电子邮件和密码。

还有一个formData状态,用于存储用户名、电子邮件和密码输入字段的值。每当用户输入输入框时,handleChange函数就会更新formData状态。

登录组件中,编写以下几行代码:

import React from "react";
import Authnavbar from "../components/Authnavbar";

function Login() {
  const [formData, setFormData] = React.useState({
    username: "",
    password: "",
  });

  const handleChange = (event) => {
    setFormData((prevState) => ({
      ...prevState,
      [event.target.name]: event.target.value,
    }));
  };

  return (
    <>
      <Authnavbar type= "login"/>
      <form>
        <input
          type= "text"
          name= "username"
          placeholder= "Username..."
          onChange={handleChange}
          value={formData.username}
        />
        <input
          type= "password"
          name= "password"
          placeholder= "Password..."
          onChange={handleChange}
          value={formData.password}
        />
        <div>
          <button>Log In</button>
        </div>
      </form>
    </>
  );
}

export default Login;

登录页面与注册页面非常相似,只是登录表单中没有电子邮件输入字段,formData对象状态也缺少电子邮件属性。

现在,用以下代码行替换index.css文件中的代码,为应用程序添加样式:

*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body{
  color: #333333;
  background-color: #E8F7F5;
  inline-size: 50%;
  margin: auto;
  font-family: "Montserrat", sans-serif;
}

input{
  padding: 0.7rem 1rem;
  border-radius: 10px;
  border: none;
  outline: none;
  color: #333333;
  background-color: #FFFFFF;
  font-family: "Montserrat", sans-serif;
  inline-size: 100%;
}

input::placeholder{
  font-family: "Montserrat", sans-serif;
  font-weight: 500;
}

button{
  padding: 0.7rem 1rem;
  background-color: #00C3A5;
  color: #FFFFFF;
  font-family: "Montserrat", sans-serif;
  font-size: 14px;
  border-radius: 7px;
  border: none;
}

form{
  margin-block-start: 25%;
  display: flex;
  flex-direction: column;
  gap: 2rem;
  align-items: center;
}

nav{
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 0;
}

.link{
  text-decoration: none;
  color: #00C3A5;
}

设计好应用程序后,运行下面的命令启动应用程序:

npm run dev

运行上述命令后,您将获得http://localhost:5173/ 链接在网络浏览器上导航至该链接,即可查看您的应用程序。

使用您定义的样式后,注册页面应如下所示:

班卡注册页面

登录页面应如下图所示:

班卡登录页面

在创建了 React 应用程序后,您需要创建一个新的 Back4app 应用程序来处理身份验证。

创建新的 Back4App 应用程序

要使用 Back4app,您需要有一个账户。如果您没有账户,可以免费注册

在本教程中,您将使用 Back4app AI 代理创建一个新的 Back4app 应用程序。Back4app AI 代理是一个 AI 助手,可帮助您使用提示在 Back4app 上执行任务。

登录您的 Back4app 账户,找到并点击仪表板导航栏上的 “AI Agent“按钮(见下图)。

Back4app 主页控制面板

要使用 Back4app AI Agent 生成应用程序,请输入以下提示:

create a new application named react-authentication

您应该会收到类似下图所示的回复:

使用人工智能代理创建新的 Back4app 应用程序

如上图所示,Back4app AI 代理创建了一个名为 react-authentication 的应用程序。您可以在 “我的应用程序 “网页上找到该应用程序。

您也可以使用 Back4app 直观的用户界面(UI)创建新的 Back4app 应用程序。

在 Back4app 上的 react-authentication 应用程序中,创建一个钱包类。该钱包类将保存有关用户钱包的宝贵信息。

您可以根据下面的提示使用人工智能代理创建类:

Create a Wallet class and add the following fields: balance, owner(relation to the User class indicating which user owns the wallet), createdAt, and updatedAt in the react-authentication app

AI Agent 将启动创建钱包类的过程,并添加指定的内容,如下图所示。

使用人工智能代理创建钱包类

将 React 应用程序连接到 Back4app

创建 Back4app 应用程序后,您需要使用 Parse SDK 将 Back4app 应用程序连接到 React 应用程序。

运行以下命令在应用程序中安装 Parse:

npm install parse

接下来,在应用程序组件中导入Parse对象,并使用 Back4app 应用程序密钥对其进行配置,从而在应用程序中对其进行初始化。

就像这样

import Parse from 'parse';

Parse.initialize('YOUR_APP_ID', 'YOUR_JAVASCRIPT_KEY');
Parse.serverURL = '<https://parseapi.back4app.com/>';

"YOUR_APP_ID ""YOUR _ JAVASCRIPT_KEY "替换为 Back4App 提供的相应密钥。使用 Back4app AI 代理创建应用程序后,您可以在屏幕上找到您的应用程序密钥。

应用程序证书

请注意,应始终在应用程序中妥善保管密钥,最好使用环境变量。

使用 Parse SDK 实现用户身份验证

初始化 Parse 后,您就可以在 React 应用程序中实现用户身份验证了。

Back4App 会自动为用户身份验证提供一个User类。该类有用户名密码电子邮件等默认字段。

注册组件中添加以下代码行,以便在 React 应用程序中实现用户注册。

import Parse from "parse"
import { useNavigate } from "react-router-dom";

const navigate = useNavigate();

const signUpUser = async () => {
  try {
    const newUser = new Parse.User();
    newUser.set("username", formData.username);
    newUser.set("email", formData.email);
    newUser.set("password", formData.password);
    const user = await newUser.signUp();

    let Wallet = Parse.Object.extend("Wallet");
    let wallet = new Wallet();

    let userPointer = {
      __type: "Pointer",
      className: "_User",
      objectId: user.id,
    };

    wallet.set("owner", userPointer);
    wallet.set("balance", 100);
    wallet.save();

    console.log(`${user} have successfully signed up`);
    navigate("/login");
  } catch (error) {
    console.log("you encountered an error signing up");
  }
};

上面的代码块使用react-router-dom中的useNavigate钩子,以编程方式导航到不同的路由。useNavigate钩子会返回一个分配给变量navigate 的 navigate 函数。

signUpUser函数负责注册新用户。该函数使用Parse.User方法创建了一个新的 Parse 用户对象newUser,并将其用户名电子邮件密码属性值设置为formData对象状态的相应属性值。然后在newUser对象上异步调用signUp方法。

代码创建新用户后,使用Parse.Object.extend方法定义了一个名为 “Wallet “的 Parse 类。

然后,创建一个userPointer对象,该对象代表一个指向用户的指针,类名为_User,以及新注册用户的对象 ID。代码使用set方法将钱包的所有者设置为userPointer对象,并将钱包的初始余额设置为 100。

注册成功后,函数会记录一条成功信息,并使用navigate函数重定向到登录路径。如果在注册过程中出现错误,则会捕获错误并记录错误信息。

接下来,创建一个handleSubmit函数,调用signUpUser函数。使用onSubmit事件处理程序将此函数绑定到注册表单。

这样,当用户提交注册表单时,就会自动触发 handleSubmit 函数。

handleSubmit函数应该如下所示:

const handleSubmit = (event) => {
  event.preventDefault();
  signUpUser();
};

为实现用户登录,您将创建一个logInUser函数,用于保存登录用户的逻辑。

将下面的代码块添加到登录组件中:

import Parse from "parse"
import { useNavigate } from "react-router-dom";

const navigate = useNavigate();

const logInUser = async () => {
    try {
      const user = await Parse.User.logIn(formData.username, formData.password);
      console.log("User logged in successfully:", user);
      navigate("/home");
    } catch (error) {
      console.log("Error logging in user:", error);
    }
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    logInUser();
  };

logInUser函数异步调用Parse.User类的logIn方法,从formData对象状态中传入用户名密码属性值。

该函数检查用户输入的用户名和密码是否与 Back4App 用户类中存储的用户名和密码一致。如果匹配,用户将成功登录。

使用onSubmit事件将handleSubmit函数绑定到登录表单。handleSubmit函数将调用logInUser函数并尝试登录用户。

登录后,Parse SDK 会管理用户的会话。你可以使用Parse.User.current方法访问当前用户。你将在主页(Home)组件中使用该方法。

打开 “主页 "组件并编写以下代码:

import React from "react";
import Parse from "parse";
import { useNavigate } from "react-router-dom";

function Home() {
  const navigate = useNavigate();
  
  const [balance, setBalance] = React.useState(0);

  const user = Parse.User.current();

  const fetchBalance = async () => {
	  const Wallet = await Parse.Object.extend("Wallet");
	  const query = new Parse.Query(Wallet);
	  query.equalTo("owner", user);
	  const wallet = await query.first();
	  setBalance(wallet.get("balance"));
};

fetchBalance();

  return (
    <>
      <nav>
        <h1 className="title">Banka</h1>
        <button>Log out</button>
      </nav>
      <div className="home">
        <p className="top">Welcome {user.get("username")}</p>

        <div className="balance-card">
          <p>Total Wallet Balance</p>
          <h1>{balance}</h1>
          <button>Top Up</button>
        </div>

        <div className="features">
          <div className="card">
            <p>Pay Bills</p>
          </div>
          <div className="card">
            <p>Airtime/Data</p>
          </div>
          <div className="card">
            <p>Transfers</p>
          </div>
          <div className="card">
            <p>Withdraw</p>
          </div>
        </div>
      </div>
    </>
  );
}

export default Home;

上面的代码块代表应用程序的主页。fetchBalance函数用于获取当前用户的钱包余额。

它使用Parse.Query方法查询 “钱包 “类,并使用query.equalTo方法对查询设置约束,以检索所有者属性等于当前用户的钱包。

query.first方法执行查询,并返回符合查询约束条件的第一个结果。

通过setBalance函数,代码将钱包余额设置为余额状态。代码会显示用户姓名及其钱包余额。

在代码块的 JSX 部分,您可以在类为balance-carddiv标签中找到“充值 “按钮。

点击该按钮后,钱包余额将增加 10。为此,您将创建一个topUp函数,其中包含增加余额的逻辑。

就像这样

const topUp = async () => {
  const Wallet = await Parse.Object.extend("Wallet");
  const query = new Parse.Query(Wallet);
  query.equalTo("owner", user);
  const wallet = await query.first();
  wallet.increment("balance", 10);
  const newBalance = await wallet.save();
  setBalance(newBalance.get("balance"));
};

这段代码从 Parse 后台获取用户的钱包,使用increment方法将余额递增 10,将更新后的钱包保存回后台,并更新余额状态。使用 click 事件处理程序将topUp函数绑定到“充值 “按钮。

接下来,在主页组件中添加一个logOutUser函数,负责注销用户。该函数应如下所示

const logOutUser = async () => {
  try {
    const user = await Parse.User.logOut();
    console.log("User logged out successfully:", user);
    navigate("/");
  } catch (error) {
    console.error("Error logging out user:", error);
  }
};

logOutUser函数异步调用Parse.User类的logOut方法来注销当前用户。使用 click 事件将logOutUser函数绑定到主页组件中的“注销 “按钮。

要设置 “主页 "组件的样式,请将下面定义的 CSS 类添加到index.css文件中。

.home{
  display: flex;
  flex-direction: column;
  gap: 3rem;
  margin-block-start: 4rem;
}

.title{
  text-align: center;
  margin-block-start: 2rem;
}

.top{
  font-size: 25px;
  font-weight: 500;
}

.balance-card{
  background-color: #FFFFFF;
  inline-size: 40%;
  padding: 1rem 2rem;
  border-radius: 7px;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.features{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2rem;
}

.card{
  background-color: #FFFFFF;
  color: #00C3A5;
  margin-block-end: 1rem;
  padding: 1rem 2rem;
  font-size: 25px;
  border-radius: 10px;
}

.card:hover{
  opacity: 0.6;
}

测试应用程序

完成 React 应用程序的构建并使用 Back4app 实现用户身份验证后,您就可以开始使用 Back4app 了。

下一步是测试应用程序。为此,请在网络浏览器上导航至链接http://localhost:5173/,注册页面就会显示在您的屏幕上。

填写报名表并提交。

在班卡上注册

注册后,您可以访问 Back4app 上的应用程序控制面板确认注册是否成功。如果注册成功,Back4app 将把用户详细信息添加到应用程序的用户类中。

就像这样

注册后,应用程序会将您重定向到登录页面,您可以使用在注册表单中使用的用户名和密码登录。

例如

登录银行

登录后,屏幕上将显示主页,应该是这样的:

班卡仪表板

现在点击“充值 “按钮,将余额增加 10。

充值银行

在 Back4app 上部署 React 应用程序

要在 Back4app 上部署 React 应用程序,您需要使用 Back4app 的容器即服务(CaaS)应用程序。

Back4app 的 CaaS允许您在 Back4App 提供的云环境中部署和管理 Docker 容器。

在部署 React 应用程序之前,首先需要对应用程序进行 dockerize。为此,请在应用程序的根目录下创建一个Dockerfile,并添加以下代码行:

FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev"]

Dockerfile设置了一个 Node.js 环境,创建了一个工作目录,安装了依赖项,复制了应用程序代码,公开了一个端口,并指定了运行应用程序的默认命令。

此外,还要创建一个.dockerignore文件。在.dockerignore文件中,添加在构建 Docker 镜像时从上下文中排除的文件和目录。

例如

#.dockerignore
node_modules

由于您使用 Vite 创建了 React 应用程序,因此必须更新 Vite 配置文件以支持 Docker。在vite.config.js文件中,用下面的代码块替换现有代码:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// <https://vitejs.dev/config/>
export default defineConfig({
  plugins: [react()],
  server: {
    host: true,
    strictPort: true,
    port: 5173,
   },
})

该代码块设置服务器使用默认主机,通常是localhost。它将开发服务器监听的端口号设置为 5173 端口,并确保在指定端口不可用时,Vite 将无法启动服务器。

现在,你可以在终端运行以下命令来构建应用程序的 docker 镜像:

docker build -t quote-generator .

在尝试在 Back4app 上部署应用程序之前,请确保将应用程序推送到 GitHub 账户。推送应用程序完成后,将 GitHub 账户与 Back4app 整合。

您可以使用Back4app Github 应用程序实现这一功能。将 GitHub 与 Back4app 集成后,您就可以使用 Back4app AI 代理部署应用程序了。

要部署应用程序,请输入以下提示:

Deploy my repository <<repository-url>> on Back4app containers

在上面的代码块中,将repository-url替换为应用程序的 GitHub 仓库 URL。

在 Back4app 容器上部署应用程序

如上图所示,在与人工智能代理通信时,请提供您要部署的应用程序的 GitHub 仓库链接。

Back4app 的人工智能代理启动应用程序部署后,请等待几分钟,然后确认部署的当前状态。

例如

应用程序实时 URL

部署成功后,Back4app AI 代理会将应用程序的部署状态更新为“已部署”,并为您提供一个链接,以便您在浏览器上访问应用程序。

您可以在这个GitHub 仓库中找到完成的应用程序,在这个 URL 中找到实时应用程序。

结论

本文介绍了如何使用后台服务为 React 应用程序添加身份验证。

使用 Back4App 将用户身份验证集成到您的 React 应用程序中是一个简单直接的过程,可显著增强应用程序的安全性和功能性。

利用 Back4App 的服务,您可以专注于构建具有良好用户体验的网络应用程序,而将后台管理和身份验证任务交给可靠的平台。


Leave a reply

Your email address will not be published.