身份验证是在授予应用程序访问权限之前验证用户身份的过程。这是开发的一个重要方面,因为它不仅保护用户的数据,而且还增强了整体用户体验。我们还可以使用经过验证的详细信息来个性化用户体验,提供定制内容,并提供用户特定设置或保存的首选项等功能。
在本文中,我们将提供有关如何使用 Appwrite 在 React 应用程序中对用户进行身份验证的分步指南。我们还将了解如何利用 Appwrite 的功能来实现登录和注册功能、管理用户会话和受保护的路由。
什么是Appwrite? {#what}
Appwrite是一款免费的开源应用程序,可帮助开发人员将后端技术集成到 Web 应用程序中。作为后端服务,Appwrite 提供不同的身份验证功能,从多因素身份验证到帐户验证和恢复。这使得开发人员可以更轻松地无缝实现安全的用户身份验证。
在 React 项目中设置 Appwrite 的先决条件 {#prer}
在按照步骤将 Appwrite 集成到我们的 React 项目之前,我们需要做好以下准备:
-
对 React 和 JavaScript 有基本了解
-
一个Appwrite帐户(我们可以免费创建一个)
1.创建一个React应用程序 {#crea}
打开终端并运行以下命令:
npx create-react-app userauth
导航到项目目录:
cd userauth
2.选择Appwrite安装方式 {#choo}
Appwrite提供了多种安装选项,让我们可以选择最适合自己喜好的安装方法。以下是可用于安装 Appwrite 的一些选项:
-
码头工人。此选项利用 Docker 来简化容器化环境中的设置和管理。
-
自托管. 此选项提供直接安装在我们的服务器上,从而提供更多控制,但需要手动配置。
-
基于云的部署。这使用云提供商来提供托管服务、可扩展性和最小的设置开销。
-
Appwrite 命令行界面。这是通过在本地安装 Appwrite 来实现开发和测试目的的。
在本文中,我们将使用基于云的部署选项,因为它相对更容易设置并且为用户提供更好的可访问性。
3. 创建Appwrite项目 {#proj}
要将 Appwrite 集成到我们的应用程序中,我们必须登录我们的帐户。登录后,我们可以按照以下步骤操作:
创建一个新项目。
选择Web App作为平台。
选择localhost作为主机并命名应用程序。
- 打开 Web 浏览器并导航至仪表板。
在React App中安装Appwrite的SDK {#inst}
要将 Appwrite 集成到我们的 React 应用程序中,我们需要安装 Appwrite JavaScript SDK。我们可以通过以下步骤来做到这一点。
首先,在项目根目录下运行以下命令:
npm install appwrite
接下来,在文件夹中创建一个配置文件 ( Appwrite.js
)src
以存储 Appwrite 端点和项目 ID。
//Appwrite.js
import { Client, Account } from 'appwrite';
export const API_ENDPOINT = 'https://cloud.appwrite.io/v1'
export const PROJECT_ID = 'YOUR PROJECT ID HERE'
const client = new Client()
.setEndpoint(API_ENDPOINT)
.setProject(PROJECT_ID);
export const account = new Account(client);
export default client;
将占位符'YOUR_APPWRITE_ENDPOINT'
和'YOUR_APPWRITE_PROJECT_ID'
替换为 Appwrite 端点和项目 ID(可以从 Appwrite 仪表板获取)。
在我们的 React 应用程序中初始化 Appwrite。在我们的 mainindex.js
或App.js
文件中,使用我们之前创建的配置文件导入并初始化 Appwrite:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Appwrite } from 'appwrite';// appwrite import statement
import appwriteConfig from './appwrite';// import statement
//Initializing Appwrite
const appwrite = new Appwrite();
appwrite.setEndpoint(appwriteConfig.endpoint).setProject(appwriteConfig.project);
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);`
构建主应用程序 {#buil}
配置完成后,我们现在可以构建我们的应用程序。在此应用程序中,我们将具有登录、注册和注销逻辑,这些逻辑将利用 Appwrite SDK 中的功能。
实现注册功能 {#imp}
为了允许用户在我们的 React 应用程序中创建帐户并注册,我们需要执行以下操作。
首先,我们创建一个注册表。该表单将收集必要的信息,例如电子邮件和密码,并将其发送到 Appwrite 服务器以供用户创建:
return (
<div className="container">
<form ref={registerForm} onSubmit={handleRegistration}>
<div className="form-field-wrapper">
<label>Name:</label>
<input required type="text" name="name" placeholder="Enter name..." />
</div>
<div className="form-field-wrapper">
<label>Email:</label>
<input
required
type="email"
name="email"
placeholder="Enter email..."
/>
</div>
<div className="form-field-wrapper">
<label>Password:</label>
<input
type="password"
name="password1"
placeholder="Enter password..."
autoComplete="password1"
/>
</div>
<div className="form-field-wrapper">
<input type="submit" value="Register" className="btn" />
</div>
</form>
<p>{/* Already have an account? <Link to="/login">Login</Link> */}</p>
</div>);
接下来,我们必须创建一个函数,每次单击按钮时,该函数都会进行 API 调用以在 Appwrite 服务器中创建新用户:
import React, { useRef } from "react";// import { Link } from "react-router-dom";import { ID } from "appwrite";import { account } from "../appwrite";const Register = () => {
const registerForm = useRef(null);
const handleRegistration = async (e) => {
e.preventDefault();
const name = registerForm.current.name.value;
const email = registerForm.current.email.value;
const password1 = registerForm.current.password1.value;
try {
const response = await account.create(
ID.unique(),
email,
password1,
name
);
console.log("Registration successful:", response);
// Redirect or perform further actions upon successful registration
} catch (error) {
console.error("Registration failed:", error);
// Handle registration errors appropriately
}
};
return(
//return the form we created earlier
)
};export default Register;
在此代码段中,我们将创建一个注册表单,用于接受用户的输入并将其发送到 Appwrite SDK。以下是处理用户注册的函数的详细说明。
-
函数定义。
const handleRegistration = async (e) => { ... }
定义一个名为 的异步函数handleRegistration
,该函数接受事件对象 (e
) 作为参数。 -
防止默认表单提交。
e.preventDefault();
防止表单提交的默认行为,这通常会重新加载页面。这使我们能够使用 JavaScript 处理注册过程。 -
尝试注册。我们通过
try...catch
在 try 块中实现主要逻辑并在 catch 块中捕获潜在错误,利用该块来处理注册过程中的潜在错误。 -
使用 Appwrite 的帐户创建。在
const response = await client.account.create(email, password);
我们调用account.create
Appwrite 客户端的方法中,我们使用该方法使用用户提供的电子邮件和密码创建新的用户帐户。await
暂停函数执行,直到异步 API 调用完成。client
指初始化的Appwrite客户端实例。
用户注册后,将创建一个存储用户详细信息的新行。
实现登录功能 {#log}
为了使用 Appwrite 的 SDK 登录,我们使用了一个函数,该函数将用户的电子邮件和密码作为参数并处理身份验证过程。如果凭证有效,服务器会返回一个身份验证令牌,我们可以将其存储在客户端存储(例如本地存储或 cookie)中以供将来的 API 调用:
import React, { useRef } from "react";
// import { Link } from "react-router-dom";
import { ID } from "appwrite";
import { account } from "../appwrite";
const Login = () => {
const loginForm = useRef(null);
const handleLogin = async (e) => {
e.preventDefault();
const name = loginForm.current.name.value;
const email = loginForm.current.email.value;
const password1 = loginForm.current.password1.value;
try {
const response = await account.createEmailSession(email, password1);
console.log("User has been Logged In:", response);
// Redirect or perform further actions upon successful registration
} catch (error) {
console.error("Login failed:", error);
// Handle registration errors appropriately
}
};
return (
<div className="container">
<form ref={loginForm} onSubmit={handleLogin}>
<div className="form-field-wrapper">
<label>Name:</label>
<input required type="text" name="name" placeholder="Enter name..." />
</div>
<div className="form-field-wrapper">
<label>Email:</label>
<input
required
type="email"
name="email"
placeholder="Enter email..."
/>
</div>
<div className="form-field-wrapper">
<label>Password:</label>
<input
type="password"
name="password1"
placeholder="Enter password..."
autoComplete="password1"
/>
</div>
<div className="form-field-wrapper">
<input type="submit" value="Login" className="btn" />
</div>
</form>
<p>{/* Already have an account? <Link to="/login">Login</Link> */}</p>
</div>
);
};
export default Login;
就像在注册逻辑中一样,我们正在创建一个返回表单的组件。该表单接受用户输入并将其发送到一个函数,该函数验证详细信息并在授权的情况下登录用户。
以下是实现登录逻辑的代码细分:
-
函数定义。该
handleLogin
函数的第一行const handleLogin = async (e) => { ... }
定义了一个名为 的异步函数handleLogin
,该函数将事件对象 (e
) 作为输入。该async
关键字表明它使用 Promise 来处理异步操作。我们还使用该preventDefault
方法来阻止浏览器的默认表单提交行为。 -
调用Appwrite的会话创建。
const response = await client.account.createSession(email, password);
用于调用account.createSession
,如果提供的详细信息与存储中保存的详细信息相对应,它将创建一个会话并登录用户。
创建受保护的页面 {#prot}
受保护的页面是未经身份验证的用户无法访问的页面。例如,我们有一个显示用户详细信息的个人资料页面,但我们希望单独登录的用户可以访问该页面。要使用 Appwrite 实现此目的,我们必须首先创建一个函数来跟踪经过身份验证的用户。该函数是在一个单独的页面上创建的,我们将其连接到需要验证的其他页面。
创建身份验证挂钩 {#hook"}
为了在 React 应用程序中管理用户身份验证和会话跟踪,我们可以创建一个名为 的自定义挂钩useAuth
。该挂钩将跟踪经过身份验证的用户会话并提供必要的功能来检查身份验证状态:
import { createContext, useState, useEffect, useContext } from "react";import { account } from "../appwrite";import { useNavigate } from "react-router-dom";import { ID } from "appwrite";const AuthContext = createContext();export const AuthProvider = ({ children }) => {
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [user, setUser] = useState(null);
useEffect(() => {
checkUserStatus();
}, []);
const checkUserStatus = async () => {
try {
const accountDetails = await account.get();
setUser(accountDetails);
} catch (error) {
console.error("Error checking user status:", error); // Log or handle error
} finally {
setLoading(false);
}
};
const contextData = {
user,
loading, // Add loading state to context
};
return (
<AuthContext.Provider value={contextData}>
{loading ? <div>Loading...</div> : children}
</AuthContext.Provider>
);};// Custom Hookexport const useAuth = () => {
return useContext(AuthContext);};export default AuthContext;
在该AuthProvider
组件中,我们使用useState
和useEffect
挂钩来跟踪用户的身份验证状态。我们还通过从 Appwrite 的 SDK 获取帐户详细信息来初始化身份验证状态。自定义挂钩useAuth
通过提供对当前用户和加载状态的访问权限,允许其他组件使用身份验证上下文。
创建单独的受保护路由 {#sep}
为了根据用户的身份验证状态限制对某些页面的访问,我们需要一个能够访问我们之前创建的挂钩的组件。该ProtectedRoute
组件将检查用户是否已通过身份验证,如果未通过身份验证,则呈现预期页面或将用户重定向到登录页面:
import { Outlet, Navigate } from "react-router-dom";
import { useAuth } from "./useAuth"; // imports the authentication hook
const ProtectedRoute = () => {
const { user } = useAuth();
return user ? <Outlet /> : <Navigate to="/login" />;
};
export default ProtectedRoute;
在ProtectedRoute
组件中,我们使用useAuth
钩子来检查用户是否经过身份验证。如果用户通过身份验证,children
则会呈现(预期页面)。否则,用户将使用Navigate
来自 的组件重定向到登录页面react-router-dom
。
对目标页面应用保护 {#int}
要将保护应用到我们想要的页面,我们可以ProtectedRoute
在主 JSX 文件的路由设置中使用该组件:
import "./App.css";import { BrowserRouter as Router, Routes, Route } from "react-router-dom";// import PrivateRoutes from "./utils/PrivateRoutes";import { AuthProvider } from "./utils/useAuth";import Home from "./pages/Home";import Profile from "./pages/Profile";import Login from "./pages/login";import Register from "../src/pages/registeration";import NavBar from "./Components/NavBar";import Logout from "./pages/Logout";import ProtectedRoute from "./utils/ProtectedRoute";function App() {
return (
<Router>
<AuthProvider>
<NavBar />
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/logout" element={<Logout />} />
<Route path="/register" element={<Register />} />
<Route path="/" element={<Home />} />
<Route
path="/profile"
element={
<ProtectedRoute>
<Profile />
</ProtectedRoute>
}
/>
</Routes>
</AuthProvider>
</Router>
);}export default App;
在前面的代码片段中,我们使用ProtectedRoute
组件来包装Home
组件。这使其成为ProtectedRoute
组件的子组件,并确保Home
只有经过身份验证的用户才能访问该组件。
在个人资料页面上显示用户的详细信息 {#disp}
当用户通过身份验证后,我们可能希望显示用户的详细信息,例如用户名、电子邮件、个人资料图片等。这还可以包括显示他们的购物车信息和愿望清单。这可以通过从 Appwrite 的 SDK 检索用户信息并将其呈现在 React 组件中来实现:
import React, { useState, useEffect } from 'react';import appwrite from './appwrite';function UserDetails() {
const [user, setUser] = useState(null);
useEffect(() => {
const fetchUserDetails = async () => {
try {
const response = await appwrite.account.get();
setUser(response);
} catch (error) {
console.error(error);
}
};
fetchUserDetails();
}, []);
return (
<div>
{user && (
<div>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<img src={user.avatar} alt="User Avatar" />
</div>
)}
</div>
);}export default UserDetails;
在前面的代码中,我们使用钩子useEffect
在组件加载时获取用户详细信息。我们还调用该appwrite.account.get()
方法来检索用户的信息并将其存储在user
状态中。一旦用户详细信息可用,我们就可以在组件中呈现用户的姓名和电子邮件:
创建注销功能 {#func}
为了实现注销功能,我们必须创建一个删除用户会话并清除当前用户数据的函数:
// Logout.jsximport React from "react";import { Link } from "react-router-dom";import { account } from "../appwrite";import "./Logout.css"; // Import the CSS filefunction Logout() {
const logoutUser = async () => {
try {
const response = await account.deleteSession("current");
console.log("Logout successful:", response);
// Redirect or perform further actions upon successful logout
} catch (error) {
console.error("Logout failed:", error);
// Handle logout errors appropriately
}
};
return (
<div className="logout-container">
<h2 className="logout-message">Are you sure you want to log out?</h2>
<div className="logout-options">
<p>
<Link to="/" className="header-link">
No, I don't </Link>
</p>
<p>
<button className="logout-button" onClick={logoutUser}>
Yes, I'm sure </button>
</p>
</div>
</div>
);}export default Logout;
在该logoutUser
函数中,我们使用 方法account.deleteSession
来删除当前用户会话,从而有效地注销用户。我们还可以执行其他清理操作,例如清除用户数据或重置应用程序状态。
处理 React 和 Appwrite 中的错误 {#err}
构建健壮且用户友好的 React 应用程序需要有效的错误处理,尤其是在使用 Appwrite 等后端服务时。这是因为用户的体验很容易因 API 调用失败、网络错误、无效的用户输入或意外的服务器行为而受到干扰。以下是我们可以用来在项目中优雅地处理错误的一些最佳实践。
-
使用 try/catch 块。就像我们之前的示例一样,
try/catch
在可能容易出错的代码周围使用块。我们可以通过在块中写入预期逻辑try
并使用该catch
块通过显示信息性消息、记录详细信息或将用户重定向到相关页面来适当处理错误来实现此目的。 -
误差边界。我们还可以利用 React 错误边界来获取子组件中的错误,而不必影响整个应用程序。
-
创建自定义错误组件。与通用错误消息相比,创建专用错误组件来根据遇到的错误类型显示用户友好的消息有助于提供更加个性化和信息丰富的体验。
结论 {#conc}
选择正确的身份验证系统是创建安全应用程序不可或缺的一部分。因此,在为应用程序选择身份验证方法时,考虑应用程序的要求、所需的安全级别以及我们想要提供的用户体验非常重要。
通过遵循本文中概述的步骤和最佳实践,我们可以使用 Appwrite 在 React 应用程序中实现可靠且用户友好的身份验证系统。