Project Templates
Social Network
您的社交网络的身份验证系统
48 分
介绍 在本教程中,您将学习如何使用 back4app 作为后端服务为您的社交网络 web 应用程序实现一个全面的身份验证系统。您将构建用户注册、登录、密码重置和会话管理的功能——这些是任何现代社交应用程序的关键特性。 back4app 是一个基于 parse server 的后端即服务 (baas) 平台,允许开发人员创建可扩展的应用程序,而无需管理服务器基础设施。其内置的用户身份验证功能使其非常适合快速实现安全的用户管理系统。 在本教程结束时,您将创建一个功能齐全的身份验证系统,类似于 back4gram 使用的系统,这是一个社交网络应用程序。您将实现带有验证的用户注册、安全登录、密码恢复和跨应用程序的持久会话,为用户提供无缝体验,同时确保他们的账户安全。 back4gram 项目: 在 这里 找到完整的代码,适用于一个 社交网络示例项目 ,使用 back4app 构建 先决条件 要完成本教程,您需要: 一个 back4app 账户。您可以在 back4app com https //www back4app com 注册一个免费账户。 一个设置好的 back4app 项目。您可以通过遵循我们的 back4app 入门指南 https //www back4app com/docs/get started/welcome 来学习如何创建新项目。 在您的本地机器上安装 node js。 对 javascript、react js 和 restful api 概念有基本了解。 熟悉现代网页开发概念(组件、状态管理等)。 步骤 1 – 理解 back4app 的用户管理系统 在深入代码之前,了解 back4app 如何处理用户管理是很重要的。back4app 基于 parse server 构建,提供了一个专门的 parse user 类,专门用于身份验证。 parse user 类 back4app 中的 parse user 类扩展了标准的 parse 对象,具有用户身份验证的专用功能。它包括几个内置字段: 用户名 用户的唯一标识符(必填) 密码 用户的密码(注册时必填,但不以可检索的形式存储) 电子邮件 用户的电子邮件地址(可选,但推荐) 电子邮件已验证 一个布尔值,指示用户是否已验证其电子邮件 认证数据 第三方认证的认证数据 您还可以添加自定义字段以存储其他用户信息,例如个人资料图片、简介或任何其他用户特定的数据。 会话管理 当用户登录时,back4app 创建一个会话令牌来标识用户的会话。此令牌用于验证后续请求,而无需用户再次登录。会话令牌由 parse sdk 自动管理,但在需要时也可以手动控制。 以下是会话流程的工作原理: 用户提供凭据(用户名/电子邮件和密码) back4app 验证凭据 如果有效,back4app 创建会话令牌 令牌被本地存储(通常在 localstorage 或类似机制中) 令牌包含在后续的 api 请求中以验证用户 让我们看看在 back4gram 应用程序中是如何实现的。parse 初始化代码通常如下所示: // initialize parse with your back4app credentials parse initialize("your app id", "your javascript key"); parse serverurl = "https //parseapi back4app com/"; back4gram 应用中的此设置允许所有组件访问 parse sdk,并在用户登录后进行身份验证请求。 安全特性 back4app 提供了多个用户管理的安全特性: 安全密码存储 密码从不以明文存储,而是自动进行哈希和加盐处理。 会话管理 用户会话可以通过 back4app 仪表板进行管理和撤销。 访问控制列表 (acls) 您可以控制谁可以读取或写入特定对象。 电子邮件验证 back4app 可以向用户发送验证电子邮件。 密码重置 内置安全密码重置功能。 现在我们了解了基础知识,让我们继续设置我们的项目。 back4gram 项目: 在 这里 找到完整的代码,作为一个 社交网络示例项目 ,使用 back4app 构建。 步骤 2 – 设置您的项目 为了演示如何使用 back4app 实现身份验证,我们将创建一个简化版本的 back4gram 社交网络应用程序。 创建一个新的 react 应用程序 首先,让我们创建一个新的 react 应用程序。打开终端并运行 npx create react app social network auth cd social network auth 安装所需的包 接下来,我们将安装必要的包 npm install parse react router dom @chakra ui/react @emotion/react @emotion/styled framer motion 这些包提供 parse back4app 的 javascript sdk react router dom 用于页面路由 @chakra ui/react 用于构建 ui 的组件库 项目结构 让我们为我们的认证系统设置一个基本的文件结构 src/ ├── components/ │ └── ui/ │ ├── field js │ └── toaster js ├── pages/ │ ├── signuppage js │ ├── loginpage js │ ├── resetpasswordpage js │ ├── profilepage js │ └── feedpage js ├── app js └── index js 配置 parse sdk 现在,让我们在应用程序中初始化 parse。创建一个名为 src/parseconfig js import parse from 'parse/dist/parse min js'; // initialize parse parse initialize("your app id", "your javascript key"); parse serverurl = "https //parseapi back4app com/"; export default parse; 将 your app id 和 your javascript key 替换为您的 back4app 项目凭据。您可以在 back4app 仪表板的应用设置 > 安全性和密钥中找到这些信息。 接下来,让我们更新 src/index js 以导入我们的 parse 配置: import react from 'react'; import reactdom from 'react dom/client'; import ' /index css'; import app from ' /app'; import ' /parseconfig'; const root = reactdom createroot(document getelementbyid('root')); root render( \<react strictmode> \<app /> \</react strictmode> ); 设置路由 现在,让我们在 src/app js 中设置基本路由结构: import react from 'react'; import { browserrouter as router, routes, route } from 'react router dom'; import {provider} from " /components/ui/provider"; // import pages import signuppage from ' /pages/signuppage'; import loginpage from ' /pages/loginpage'; import resetpasswordpage from ' /pages/resetpasswordpage'; import profilepage from ' /pages/profilepage'; import feedpage from ' /pages/feedpage'; function app() { return ( \<provider> \<router> \<routes> \<route path="/signup" element={\<signuppage />} /> \<route path="/login" element={\<loginpage />} /> \<route path="/reset password" element={\<resetpasswordpage />} /> \<route path="/profile" element={\<profilepage />} /> \<route path="/feed" element={\<feedpage />} /> \<route path="/" element={\<loginpage />} /> \</routes> \</router> \</provider> ); } export default app; 创建 ui 组件 在我们开始构建身份验证页面之前,让我们创建一些可重用的 ui 组件。 首先,让我们创建 src/components/ui/toaster js // a simple toast notification system export const toaster = { create ({ title, description, type }) => { alert(`${title} ${description}`); // in a real app, you would use chakra ui's toast system } }; 然后,创建 src/components/ui/field js import react from 'react'; import { formcontrol, formlabel, formerrormessage, formhelpertext } from '@chakra ui/react'; export const field = ({ label, children, errortext, helpertext, rest }) => { return ( \<formcontrol isinvalid={!!errortext} { rest}> {label && \<formlabel>{label}\</formlabel>} {children} {errortext ? ( \<formerrormessage>{errortext}\</formerrormessage> ) helpertext ? ( \<formhelpertext>{helpertext}\</formhelpertext> ) null} \</formcontrol> ); }; 现在我们准备好实现我们的认证系统了! back4gram 项目: 在 这里 找到完整的代码,适用于一个 社交网络示例项目 ,构建于 back4app 步骤 3 – 创建用户注册系统 让我们开始实现注册页面。这个页面将允许新用户通过提供用户名、电子邮件和密码来创建账户。 创建一个名为 src/pages/signuppage js import react, { usestate } from 'react'; import { usenavigate, link as routerlink } from 'react router dom'; import { box, button, heading, input, vstack, link, text, flex } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function signuppage() { const \[username, setusername] = usestate(''); const \[email, setemail] = usestate(''); const \[password, setpassword] = usestate(''); const \[confirmpassword, setconfirmpassword] = usestate(''); const \[isloading, setisloading] = usestate(false); const \[showpassword, setshowpassword] = usestate(false); const \[errors, seterrors] = usestate({}); const navigate = usenavigate(); const validateform = () => { const newerrors = {}; if (!username trim()) { newerrors username = 'username is required'; } if (!email trim()) { newerrors email = 'email is required'; } else if (!/\s+@\s+\\ \s+/ test(email)) { newerrors email = 'email is invalid'; } if (!password) { newerrors password = 'password is required'; } else if (password length < 6) { newerrors password = 'password must be at least 6 characters'; } if (password !== confirmpassword) { newerrors confirmpassword = 'passwords do not match'; } seterrors(newerrors); return object keys(newerrors) length === 0; }; const handlesignup = async (e) => { e preventdefault(); if (!validateform()) { return; } setisloading(true); try { // create a new user using parse const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); await user signup(); toaster create({ title 'success', description 'account created successfully!', type 'success', }); navigate('/feed'); } catch (error) { console error('error signing up ', error); toaster create({ title 'error', description error message, type 'error', }); } finally { setisloading(false); } }; return ( \<box maxw="400px" mx="auto" p={4}> \<vstack spacing={6} align="stretch"> \<heading textalign="center">create an account\</heading> \<form onsubmit={handlesignup}> \<vstack spacing={4} align="stretch"> \<field isinvalid={!!errors username}> \<field label>username\</field label> \<input type="text" value={username} onchange={(e) => setusername(e target value)} /> {errors username && ( \<field errortext>{errors username}\</field errortext> )} \</field> \<field isinvalid={!!errors email}> \<field label>email\</field label> \<input type="email" value={email} onchange={(e) => setemail(e target value)} /> {errors email && ( \<field errortext>{errors email}\</field errortext> )} \</field> \<field isinvalid={!!errors password}> \<field label>password\</field label> \<flex position="relative"> \<input type={showpassword ? 'text' 'password'} value={password} onchange={(e) => setpassword(e target value)} /> \<button aria label={showpassword ? 'hide password' 'show password'} size="xs" position="absolute" right="0 25rem" top="50%" transform="translatey( 50%)" onclick={() => setshowpassword(!showpassword)} zindex={2} \> {showpassword ? 'hide' 'show'} \</button> \</flex> {errors password && ( \<field errortext>{errors password}\</field errortext> )} \</field> \<field isinvalid={!!errors confirmpassword}> \<field label>confirm password\</field label> \<input type={showpassword ? 'text' 'password'} value={confirmpassword} onchange={(e) => setconfirmpassword(e target value)} /> {errors confirmpassword && ( \<field errortext>{errors confirmpassword}\</field errortext> )} \</field> \<button type="submit" colorscheme="blue" isloading={isloading} mt={2} \> sign up \</button> \</vstack> \</form> \<text textalign="center"> already have an account?{' '} \<link as={routerlink} to="/login" color="blue 400"> log in \</link> \</text> \</vstack> \</box> ); } export default signuppage; 此代码创建了一个注册表单,具有以下功能: 表单验证 在提交之前检查所有必填字段是否正确填写 密码可见性切换 允许用户查看他们正在输入的内容 错误处理 对于验证和注册失败,显示适当的错误消息 加载状态 在注册过程中显示加载指示器 理解 back4app 的用户注册流程 这段代码的关键部分是 handlesignup 函数,它使用 back4app 的 parse user 类来创建一个新用户: const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); await user signup(); 当你调用 signup() , back4app: 验证提供的数据 安全地哈希密码 在数据库中创建新用户 创建并返回会话令牌 会话令牌会被 parse sdk 自动存储 成功注册后,用户会自动登录,因此我们可以直接将他们重定向到信息流页面。 在 back4gram 应用中,这在 signuppage js 中以类似的方式实现。主要区别在于 back4gram 的实现使用了更高级的 ui 组件,并可能包括额外的字段或验证逻辑。 注册功能完成后,让我们继续实现登录功能。 back4gram 项目: 在 这里 找到完整的代码, 社交网络示例项目 是用 back4app 构建的。 步骤 4 – 实现用户登录 现在,让我们创建登录页面,允许用户使用他们的凭据进行身份验证。 创建一个名为 src/pages/loginpage js import react, { usestate, useeffect } from 'react'; import { usenavigate, link as routerlink } from 'react router dom'; import { box, heading, input, button, text, vstack, link, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function loginpage() { const \[username, setusername] = usestate(''); const \[password, setpassword] = usestate(''); const \[isloading, setisloading] = usestate(false); const \[error, seterror] = usestate(''); const \[currentuser, setcurrentuser] = usestate(null); const navigate = usenavigate(); // check if a user is already logged in useeffect(() => { const checkcurrentuser = async () => { try { const user = await parse user current(); if (user) { setcurrentuser(user); navigate('/feed'); } } catch (error) { console error('error checking current user ', error); } }; checkcurrentuser(); }, \[navigate]); const handlelogin = async (e) => { e preventdefault(); if (!username || !password) { seterror('username and password are required'); return; } setisloading(true); try { // login with parse const loggedinuser = await parse user login(username, password); toaster create({ title 'login successful!', description `welcome back, ${loggedinuser getusername()}!`, type 'success', }); // redirect to feed after successful login navigate('/feed'); } catch (error) { toaster create({ title 'login failed', description error message, type 'error', }); seterror(error message); } finally { setisloading(false); } }; return ( \<box maxw="md" mx="auto" p={8} border="1px solid" bordercolor="gray 600" borderradius="md"> \<heading as="h1" size="xl" mb={6} textalign="center"> social network login \</heading> \<form onsubmit={handlelogin}> \<vstack spacing={4}> \<field label="username"> \<input type="text" value={username} onchange={(e) => setusername(e target value)} placeholder="your username" required /> \</field> \<field label="password" errortext={error} \> \<input type="password" value={password} onchange={(e) => setpassword(e target value)} placeholder="your password" required /> \</field> \<link as={routerlink} to="/reset password" alignself="flex end" fontsize="sm"> forgot password? \</link> \<button colorscheme="blue" width="full" type="submit" isloading={isloading} \> log in \</button> \</vstack> \</form> \<text textalign="center" mt={6}> don't have an account?{' '} \<link as={routerlink} to="/signup" color="blue 500"> sign up \</link> \</text> \</box> ); } export default loginpage; 此登录页面具有以下功能: 自动重定向 如果用户已经登录,他们会自动重定向到信息流页面 表单验证 确保在提交之前提供用户名和密码 错误处理 显示适当的错误消息以应对登录失败的尝试 加载状态 在登录过程中显示加载指示器 密码重置链接 提供指向密码重置页面的链接 理解 back4app 的登录过程 这段代码的关键部分是: 检查是否存在已登录的用户,使用 parse user current() 使用 parse user login(username, password) 当用户使用 back4app 登录时: 凭据被发送到服务器进行验证 如果有效,将生成并返回会话令牌 parse sdk 会自动存储此令牌 用户对象将与当前用户的数据一起返回 存储的会话令牌随后由 parse sdk 自动用于所有后续请求,允许用户保持登录状态。 在 back4gram 应用中,登录系统的实现方式类似于 loginpage js , 但具有更高级的 ui 组件和可能的附加功能,如社交登录选项。 现在让我们继续实现密码重置功能。 back4gram 项目: 在 这里 找到完整的代码,适用于一个 社交网络示例项目 ,该项目是使用 back4app 构建的。 步骤 5 – 密码重置功能 接下来,让我们创建一个密码重置页面,允许用户在忘记密码时恢复他们的账户。 创建一个名为 src/pages/resetpasswordpage js import react, { usestate } from 'react'; import { link as routerlink } from 'react router dom'; import { box, heading, input, button, text, vstack, link, alert, alerticon, alerttitle, alertdescription, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function resetpasswordpage() { const \[email, setemail] = usestate(''); const \[isloading, setisloading] = usestate(false); const \[error, seterror] = usestate(''); const \[issuccess, setissuccess] = usestate(false); const handleresetpassword = async (e) => { e preventdefault(); if (!email) { seterror('email is required'); return; } // basic email validation const emailregex = /^\[^\s@]+@\[^\s@]+\\ \[^\s@]+$/; if (!emailregex test(email)) { seterror('invalid email format'); return; } setisloading(true); seterror(''); try { // request password reset await parse user requestpasswordreset(email); setissuccess(true); toaster create({ title 'email sent', description 'check your inbox for password reset instructions ', type 'success', }); } catch (error) { toaster create({ title 'reset request failed', description error message, type 'error', }); seterror(error message); } finally { setisloading(false); } }; return ( \<box maxw="md" mx="auto" p={8} border="1px solid" bordercolor="gray 600" borderradius="md"> \<heading as="h1" size="xl" mb={6} textalign="center"> reset password \</heading> {issuccess ? ( \<alert status="success" borderradius="md"> \<alerticon /> \<box> \<alerttitle>email sent successfully!\</alerttitle> \<alertdescription> check your inbox for password reset instructions \</alertdescription> \</box> \</alert> ) ( \<form onsubmit={handleresetpassword}> \<vstack spacing={4}> \<text> enter your email and we'll send you instructions to reset your password \</text> \<field label="email" errortext={error} \> \<input type="email" value={email} onchange={(e) => setemail(e target value)} placeholder="your email address" required /> \</field> \<button colorscheme="blue" width="full" type="submit" isloading={isloading} \> send instructions \</button> \<link as={routerlink} to="/login" color="blue 500"> back to login \</link> \</vstack> \</form> )} \</box> ); } export default resetpasswordpage; 此密码重置页面包括 电子邮件验证 确保提供有效的电子邮件格式 成功状态 在重置电子邮件发送后显示成功消息 错误处理 如果重置请求失败,显示适当的错误消息 加载状态 在重置请求过程中显示加载指示器 理解 back4app 的密码重置过程 此代码的关键部分是使用 back4app 的 parse user requestpasswordreset(email) 方法向用户发送密码重置电子邮件。 当用户请求使用 back4app 重置密码时 back4app 验证该电子邮件是否存在于数据库中 如果找到该电子邮件,将向用户发送重置电子邮件 该电子邮件包含一个带有安全令牌的链接 当用户点击该链接时,他们会被引导到密码重置页面 在设置新密码后,他们可以使用新凭据登录 在 back4gram 应用中,密码重置功能的实现方式类似于 resetpasswordpage js , 使用相同的 back4app api 方法,但可能具有更高级的 ui 组件或附加功能。 现在我们已经实现了核心认证功能,让我们专注于会话管理。 back4gram 项目: 在 这里 找到完整的代码, 社交网络示例项目 ,该项目是使用 back4app 构建的。 步骤 6 – 会话管理和持久性 任何认证系统的关键方面之一是适当的会话管理。这确保用户在浏览应用程序时保持登录状态,并且他们的会话是安全的。 让我们创建一个简化版的动态页面,以演示会话检查和管理: 创建一个名为 src/pages/feedpage js import react, { usestate, useeffect } from 'react'; import { usenavigate } from 'react router dom'; import { box, heading, button, text, vstack, hstack, spinner, center, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; function feedpage() { const \[isloading, setisloading] = usestate(true); const \[currentuser, setcurrentuser] = usestate(null); const navigate = usenavigate(); // check if user is authenticated useeffect(() => { const checkauth = async () => { try { console log('checking authentication '); const user = await parse user current(); if (!user) { console log('no user found, redirecting to login'); navigate('/login'); return; } console log('user authenticated ', user id, user get('username')); setcurrentuser(user); setisloading(false); } catch (error) { console error('error checking authentication ', error); navigate('/login'); } }; checkauth(); }, \[navigate]); // function to handle logout const handlelogout = async () => { try { await parse user logout(); navigate('/login'); } catch (error) { console error('error logging out ', error); toaster create({ title 'error', description 'failed to log out please try again ', type 'error', }); } }; if (isloading) { return ( \<center h="100vh"> \<spinner size="xl" /> \</center> ); } return ( \<box maxw="800px" mx="auto" p={8}> \<hstack justify="space between" mb={8}> \<heading>social network feed\</heading> \<hstack> \<text>welcome, {currentuser get('username')}\</text> \<button onclick={handlelogout} colorscheme="red" variant="outline"> log out \</button> \</hstack> \</hstack> \<vstack align="stretch" spacing={4}> \<box p={4} borderwidth={1} borderradius="md"> \<text>this is your feed when authenticated with back4app, you'll see content here \</text> \<text mt={2}>your user id {currentuser id}\</text> \<text>your email {currentuser get('email')}\</text> \</box> \</vstack> \</box> ); } export default feedpage; 此动态页面实现了 身份验证检查 验证用户在显示内容之前是否已登录 自动重定向 如果未找到用户会话,则重定向到登录页面 注销功能 允许用户注销并清除其会话 用户信息显示 显示当前登录用户的信息 理解 back4app 的会话管理 back4app 以多种方式处理会话: 自动会话存储 parse sdk 在登录后自动存储会话令牌 当前用户访问 您可以使用 parse user current() 会话过期 会话通常在设定的时间后过期(可在 back4app 中配置) 注销 您可以使用 parse user logout() 在像 back4gram 这样的生产应用中,会话管理通常更为复杂。在 back4gram 的 messagespage js 文件中,我们可以看到组件开始时如何检查身份验证: useeffect(() => { const checkauth = async () => { try { console log('checking authentication '); const user = await parse user current(); if (!user) { console log('no user found, redirecting to login'); navigate('/login'); return; } console log('user authenticated ', user id, user get('username')); setcurrentuser(user); fetchconversations(user); } catch (error) { console error('error checking authentication ', error); navigate('/login'); } }; checkauth(); // clean up subscriptions when component unmounts // }, \[navigate]); 在使用 back4app 的 react 应用中,在组件级别检查身份验证的模式是常见的。 会话安全考虑 在使用 back4app 实现会话管理时,请考虑以下安全实践: 自动会话失效 配置 back4app 在一定时间不活动后使会话失效 安全存储 确保会话令牌安全存储(parse sdk 会自动处理此事) 仅使用 https 始终使用 https 以防止会话令牌被拦截 在敏感操作时注销 对于更改密码等敏感操作,要求重新认证 现在让我们看看如何实现个人资料管理,以完成我们的认证系统。 back4gram 项目: 在 这里 找到完整的代码,适用于一个 社交网络示例项目 ,该项目是使用 back4app 构建的 步骤 7 – 添加用户个人资料管理 我们认证系统的最后一部分是用户个人资料管理。这允许用户查看和更新他们的个人资料信息。 创建一个名为 src/pages/profilepage js 的文件。 import react, { usestate, useeffect } from 'react'; import { usenavigate } from 'react router dom'; import { box, button, heading, text, vstack, hstack, input, textarea, avatar, formcontrol, formlabel, spinner, center, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function profilepage() { const \[user, setuser] = usestate(null); const \[username, setusername] = usestate(''); const \[email, setemail] = usestate(''); const \[bio, setbio] = usestate(''); const \[isloading, setisloading] = usestate(true); const \[isupdating, setisupdating] = usestate(false); const \[selectedfile, setselectedfile] = usestate(null); const \[avatarurl, setavatarurl] = usestate(null); const navigate = usenavigate(); // fetch user data useeffect(() => { const fetchuserdata = async () => { try { const currentuser = await parse user current(); if (!currentuser) { navigate('/login'); return; } setuser(currentuser); setusername(currentuser get('username') || ''); setemail(currentuser get('email') || ''); setbio(currentuser get('bio') || ''); // get avatar if available const avatar = currentuser get('avatar'); if (avatar) { setavatarurl(avatar url()); } setisloading(false); } catch (error) { console error('error fetching user data ', error); toaster create({ title 'error', description 'failed to load profile data', type 'error', }); navigate('/login'); } }; fetchuserdata(); }, \[navigate]); // handle profile update const handleupdateprofile = async (e) => { e preventdefault(); setisupdating(true); try { if (!user) return; user set('username', username); user set('email', email); user set('bio', bio); // handle avatar upload if a file is selected if (selectedfile) { const parsefile = new parse file(selectedfile name, selectedfile); await parsefile save(); user set('avatar', parsefile); setavatarurl(parsefile url()); } await user save(); toaster create({ title 'success', description 'profile updated successfully', type 'success', }); } catch (error) { console error('error updating profile ', error); toaster create({ title 'error', description error message, type 'error', }); } finally { setisupdating(false); } }; // handle avatar selection const handlefilechange = (e) => { if (e target files && e target files\[0]) { setselectedfile(e target files\[0]); // create a preview url const previewurl = url createobjecturl(e target files\[0]); setavatarurl(previewurl); } }; // handle logout const handlelogout = async () => { try { await parse user logout(); navigate('/login'); } catch (error) { console error('error logging out ', error); } }; if (isloading) { return ( \<center h="100vh"> \<spinner size="xl" /> \</center> ); } return ( \<box maxw="800px" mx="auto" p={8}> \<hstack justify="space between" mb={8}> \<heading>your profile\</heading> \<button onclick={handlelogout} colorscheme="red" variant="outline"> log out \</button> \</hstack> \<box p={8} borderwidth={1} borderradius="md"> \<form onsubmit={handleupdateprofile}> \<vstack spacing={6} align="start"> \<hstack spacing={8} w="full" align="start"> \<vstack align="center" minw="150px"> \<avatar size="2xl" src={avatarurl} name={username} mb={4} /> \<formcontrol> \<formlabel htmlfor="avatar upload" cursor="pointer" textalign="center"> \<button as="span" size="sm"> change avatar \</button> \<input id="avatar upload" type="file" accept="image/ " onchange={handlefilechange} display="none" /> \</formlabel> \</formcontrol> \</vstack> \<vstack spacing={4} flex="1"> \<field label="username" w="full"> \<input value={username} onchange={(e) => setusername(e target value)} /> \</field> \<field label="email" w="full"> \<input type="email" value={email} onchange={(e) => setemail(e target value)} /> \</field> \<field label="bio" w="full"> \<textarea value={bio} onchange={(e) => setbio(e target value)} placeholder="tell us about yourself" rows={4} /> \</field> \</vstack> \</hstack> \<button type="submit" colorscheme="blue" isloading={isupdating} alignself="flex end" \> save changes \</button> \</vstack> \</form> \</box> \</box> ); } export default profilepage; this profile page provides users with the ability to 1\ view profile information see their username, email, and bio 2\ update profile details change their username, email, and bio 3\ upload a profile picture select and upload a profile image 4\ log out end their session and return to the login page \### understanding back4app's user data management let's examine the key aspects of how back4app handles user data management \#### file uploads with parse file one powerful feature of back4app is the ability to easily handle file uploads using `parse file` ```javascript if (selectedfile) { const parsefile = new parse file(selectedfile name, selectedfile); await parsefile save(); user set('avatar', parsefile); setavatarurl(parsefile url()); } 当您创建一个新的 parse file , back4app 获取您的文件(图像、文档等) 将其上传到安全存储 返回一个可以与您的用户对象一起存储的引用 通过 url 使文件可访问 添加自定义用户字段 back4app的 parse user 类可以扩展自定义字段,超出默认字段。在我们的示例中,我们添加了 bio 用户描述的文本字段 avatar 个人资料图片的文件字段 您可以为应用程序的用户资料添加所需的任何自定义字段 user set('bio', bio); 在back4gram应用程序中, profilepage js 实现了类似的功能,但具有更多功能和更复杂的用户界面。它包括额外的字段,如关注者数量、帖子统计和更强大的图像处理。 back4gram 项目: 找到 这里 完整代码,适用于一个 社交网络示例项目 ,构建于 back4app 步骤 8 – 测试和保护您的认证系统 现在我们已经构建了认证系统,让我们讨论如何正确测试和保护它。 测试认证流程 在测试您的认证系统时,您应该验证以下每个流程: 用户注册 测试用户是否可以使用有效凭据创建帐户 输入验证 验证无效输入是否出现适当的错误 登录过程 确保用户可以使用正确的凭据登录 登录失败 检查不正确凭据是否出现适当的错误 密码重置 确认密码重置流程是否端到端工作 会话持久性 验证用户在页面访问之间是否保持登录状态 注销过程 确保用户可以正确注销并终止会话 常见的安全漏洞需要避免 在构建身份验证系统时,请注意这些常见的安全问题: 密码存储 永远不要以明文存储密码。back4app 会自动为您处理这个问题。 暴力破解攻击 实施登录尝试的速率限制。back4app 提供此功能。 跨站脚本攻击 (xss) 清理用户输入以防止脚本注入。 跨站请求伪造 (csrf) 使用适当的令牌来验证请求的真实性。 不安全的直接对象引用 不要在 url 中暴露敏感的 id 或引用。 back4app 安全最佳实践 back4app 提供了几个您应该利用的安全功能: 1 类级权限 (clps) 在您的 back4app 控制面板中,您可以设置类级权限以控制谁可以读取、写入和删除对象: 前往您的 back4app 控制面板 导航到数据库 → 浏览器 点击您的用户类的 "安全性" 按钮 适当配置权限 \[图片:back4app 类级权限屏幕显示用户类安全设置] 对于用户类,典型设置包括: 仅对特定字段(用户名、头像)提供公共读取访问 没有公共写入或删除访问 只有经过身份验证的用户可以更新自己的记录 2 访问控制列表 (acls) 对于单个对象,您可以使用 acl 来控制访问: // set an acl that only allows the current user to read and write this object const useracl = new parse acl(parse user current()); userobject setacl(useracl); await userobject save(); 这确保只有创建对象的用户可以访问或修改它。 3 主密钥使用 back4app 提供一个主密钥,可以绕过安全检查。切勿在客户端代码中暴露此密钥: // never do this in client side code parse cloud usemasterkey(); // this should only be used in cloud code 相反,对于需要提升权限的操作,请使用云函数。 4 邮件验证 在您的 back4app 设置中启用邮件验证,以确保用户提供有效的电子邮件地址: 前往您的 back4app 控制面板 导航到应用设置 → 邮件设置 配置您的邮件适配器 启用邮件验证 \[图片:back4app 邮件设置配置屏幕] 5 双因素认证 为了额外的安全性,您可以使用 back4app 云函数实现双因素认证。这要求用户在登录时提供第二种验证形式(通常是发送到他们手机或电子邮件的代码)。 实施速率限制 为了防止暴力攻击,您可以使用云函数实施速率限制: // cloud function to handle login with rate limiting parse cloud define("securelogin", async (request) => { const { username, password } = request params; // check for too many failed attempts const query = new parse query("loginattempt"); query equalto("username", username); query greaterthan("createdat", new date(date now() 15 60 1000)); // last 15 minutes const attempts = await query count(); if (attempts >= 5) { throw new error("too many login attempts please try again later "); } try { // attempt to log in const user = await parse user login(username, password); return { success true, user user tojson() }; } catch (error) { // record failed attempt const loginattempt = parse object extend("loginattempt"); const attempt = new loginattempt(); attempt set("username", username); await attempt save(null, { usemasterkey true }); throw error; } }); 结论 在本教程中,您构建了一个全面的社交网络应用程序身份验证系统,使用了 back4app。您实现了用户注册、登录、密码重置和个人资料管理功能,所有这些都由 back4app 内置的用户管理功能提供支持。 让我们回顾一下您所学到的内容: back4app 的用户管理系统 您了解了 back4app 的 parse server 如何提供内置用户身份验证,使用 parse user 类。 用户注册 您实现了一个注册表单,可以在 back4app 的数据库中创建新用户帐户。 用户登录 您创建了一个登录系统,可以验证用户并管理会话。 密码重置 您添加了一个安全的密码重置功能,可以发送恢复电子邮件。 会话管理 您了解了如何维护用户会话并保护路由。 个人资料管理 您构建了一个个人资料页面,允许用户更新他们的信息并上传个人资料图片。 安全最佳实践 您探讨了如何使用 back4app 的安全功能来保护您的身份验证系统。 通过 back4app,您能够专注于创建出色的用户体验,而不是构建复杂的后端基础设施。支持 back4app 的 parse server 提供了所有必要的身份验证 api,同时确保您的用户数据保持安全。 您构建的身份验证系统构成了社交网络应用程序的基础。有了这个,您现在可以通过添加帖子、评论、点赞和直接消息等功能来扩展您的应用程序,所有这些都使用 back4app 作为后端服务。 下一步 社交登录集成 使用 back4app 的 oauth 功能添加 google、facebook 或其他提供商的登录。 增强安全性 实施双因素身份验证以增加安全性。 用户角色 为不同类型的用户设置基于角色的访问控制。 实时功能 使用 back4app 的实时查询添加实时消息和通知。 要查看 back4gram 社交网络应用程序的完整代码,您可以查看 github 仓库 https //github com/templates back4app/back4gram 。 back4app 强大的后端服务和 parse server 集成使其成为构建安全、可扩展社交网络应用程序的绝佳选择。通过利用其内置的用户管理功能,您可以以最小的努力创建一个强大的身份验证系统,从而使您能够专注于创建独特的功能,使您的应用程序脱颖而出。