如何在 React Native 应用程序中添加身份验证?
身份验证几乎是每个应用程序的核心组件。
这篇实用文章将逐步指导您开始使用 React Native 身份验证。
此外,它还将介绍身份验证的基础知识、与授权的比较、身份验证流程以及使用身份验证的好处。
什么是身份验证?
身份验证是验证某人身份的过程。一般来说,有三种验证方式,一种是通过以下方式进行验证:
- 您知道的东西(如密码、PIN 码)
- 您拥有的东西(如手机、钥匙等)
- 您的身份(如指纹、虹膜)
大多数应用程序使用第一个选项,但也有很多应用程序将多个选项结合起来以提高安全级别。这一概念被称为多因素身份验证(MFA)。
认证流程
通用身份验证流程是这样的
- 用户向服务器发送密码。
- 服务器会对密码进行散列,并与数据库中的密码散列进行比较。
- 如果哈希值匹配,服务器就会创建一个会话,并向用户发送会话令牌。相反,如果哈希值不匹配,则会出现错误。
- 然后,用户在每次请求时都会使用会话令牌。每次请求时,服务器都会检查令牌是否存在且有效。
上述流程就是所谓的令牌身份验证。其他身份验证系统包括JSON 网络令牌(JWT)、基本访问身份验证、社交登录等。
认证与授权
身份验证是验证用户身份的行为,而授权则是验证用户是否有足够的权限执行操作的行为。
授权模式包括强制访问控制(MAC)、自由访问控制(DAC)和基于角色的授权等。
身份验证的好处
让我们来看看在移动应用程序中使用身份验证的一些好处。
安全
身份验证可以保护您的应用程序免遭未经授权的访问,并保证只有合法用户才能访问您的服务。
这有助于防止数据泄露和网络攻击,确保应用程序环境安全可信。
个性化
通过身份验证,可以在应用程序中获得个性化的用户体验。当用户登录时,他们可以访问定制设置、偏好设置和针对其需求的推荐。
这种个性化使应用程序更具吸引力,更方便用户使用。它通过提供更相关、更愉快的体验来留住用户。
法律要求
有些国家的法律要求您核实用户身份。其中一个例子就是 “了解你的客户”(KYC)。
几乎所有金融应用程序都必须这样做。您必须拥有一个适当的身份验证系统,以符合这些规定或保护用户的个人信息。
如何在 React Native 应用程序中添加身份验证?
这部分文章将逐步指导如何在React Native(Expo) 应用程序中添加Back4app身份验证。
先决条件
- 对后台即服务(BaaS)有基本了解
- JavaScript IDE、Node.js 和移动模拟器或实体设备
- 读写 JavaScript 代码的能力
- 具有使用 React Native 和 Expo 的经验
- 免费的 Back4app 账户
什么是 Back4app?
Back4app 是最好的开源后端即服务(BaaS)解决方案之一。它是一个成熟可靠的平台,自 2015 年以来一直存在。
其主要功能包括实时数据库、云代码功能、自动生成 RESTful/GraphQL API 等!
Back4app 有一个易于使用且直观的管理仪表板,还有一个命令行界面 (CLI) 供高级用户使用。
它还为 JavaScript、PHP、Flutter 和 Dart 等最流行的编程语言和框架提供 SDK。
最重要的是,Back4app 提供免费层级。免费层非常适合测试和原型设计,它包括以下内容:
- 每月 25k 申请
- 250 MB 数据存储空间
- 1 GB 数据传输
- 1 GB 文件存储空间
为什么使用 Back4app?
- 支持社交认证
- 为大多数编程语言和框架提供 SDK
- 轻松设置和使用
- 卓越的客户支持
要了解 Back4app 身份验证与 Firebase 身份验证的比较,请查看《React Firebase 身份验证终极指南》。
项目介绍 – React Native 身份验证入门
我们将构建一个使用 Back4app 身份验证的可投入生产的 React Native 应用程序。该应用程序将允许用户注册、登录和管理个人资料。
除此以外,该应用程序还将有两个标签导航,一个供已通过身份验证的用户使用,另一个供未通过身份验证的用户使用。
最终产品将是这样的
开始编码吧
后台(Back4app)
在本节中,我们将创建一个 Back4app 应用程序,扩展默认用户模型,并获取连接后台所需的 API 密钥。
创建应用程序
首先,登录您的Back4app 账户,如果您还没有账户,请创建一个。
登录后,您将被重定向到应用程序列表。单击 “创建新应用程序 “创建新应用程序。
Back4app 平台允许您部署两种类型的应用程序–后端即服务(BaaS)或容器即服务(CaaS)。BaaS 中包含身份验证功能,因此请选择它。
接下来,给应用程序起一个描述性的名称,将数据库设为 NoSQL,然后点击 “创建”。
等待大约两分钟,平台就会创建应用程序。Back4app 将完成从创建应用程序层到设置数据库、安全、扩展等所有工作。
完成后,您将被重定向到数据库界面。
修改数据库
接下来,我们来谈谈数据库类。
每个 Back4app 数据库类都有以下默认字段:
+-----------+------------+-----------------------------------------+
| Data type | Name | Description |
+-----------+------------+-----------------------------------------+
| String | objectId | Object's unique identifier |
+-----------+------------+-----------------------------------------+
| Date | createdAt | Date of object creation |
+-----------+------------+-----------------------------------------+
| Date | updatedAt | Date of object's last update |
+-----------+------------+-----------------------------------------+
| ACL | ACL | Access Control List (security features) |
+-----------+------------+-----------------------------------------+
然后,用户
类还带有一些额外的字段:
+-----------+----------------+--------------------------+----------+
| Data type | Name | Default value | Required |
+-----------+----------------+--------------------------+----------+
| String | username | | yes |
+-----------+----------------+--------------------------+----------+
| String | email | | no |
+-----------+----------------+--------------------------+----------+
| Boolean | emailVerified | false | no |
+-----------+----------------+--------------------------+----------+
| String | password | | yes |
+-----------+----------------+--------------------------+----------+
| Object* | authData | {} | yes |
+-----------+----------------+--------------------------+----------+
默认的 Back4app 用户类可以满足大多数使用情况。不过,对它进行扩展也很容易。为了演示如何扩展,让我们添加一个简历(bio
)字段。
首先,点击数据库表上方的 “+ 列 “按钮。
在列创建表单中选择 “字符串 “作为数据类型,将名称设为bio
,使其成为必填项,然后点击 “添加”。
很好,你现在知道 Back4app 数据库类如何工作以及如何扩展用户模型了。
应用程序接口密钥
您需要获取应用程序的 API 密钥,以便从前台连接到后台。
要获取它们,请导航至 Back4app 应用程序,选择侧边栏上的 “安全与密钥”。注意 “客户端密钥 “和 “JavaScript 密钥”。
很好,后台就这样了。
前端(React Native)
在本节中,我们将创建 Expo 应用程序,安装组件库,设置导航,处理屏幕,最后连接前台和后台。
创建应用程序
要创建 React Native 应用程序,我们将使用create-expo-app
工具。该实用程序可以生成目录结构、配置 TypeScript 等,从而简化 React Native 应用程序的创建过程。
首先,运行以下命令:
npx create-expo-app@latest back4app-expo-auth
cd back4app-expo-auth
如果尚未安装
create-expo-app
,该命令也将安装它。
您会发现引导项目的目录结构如下:
back4app-expo-auth/
├── app - Layouts, screens
├── assets - Static assets (e.g. images, videos, fonts)
├── components - Reusable components used through the app
├── constants - Static variables & configurations
├── hooks - Custom React hooks
├── scripts - Development scripts
├── app.json - Expo configuration & metadata
├── expo-env.d.ts - Expo TypeScript declarations
├── ...
启动开发服务器
$ npx expo start
最后,按A
键在安卓模拟器上打开应用程序。或者,你也可以使用 iOS 模拟器或实体 iOS 设备。打开应用后,你会看到默认的Expo界面。
React Native Paper
为了简化用户界面开发流程,我们将使用React Native Paper。
React Native Paper 是一个易于使用的高质量组件库,适用于 React Native 应用程序。它提供了许多预制组件,几乎涵盖了所有用例。
首先通过 NPM 安装:
$ npm install react-native-paper react-native-safe-area-context
如果您要为 iOS 构建程序,您还必须链接程序库的本地部分:
npx pod-install
接下来,配置 Babel,使其不在生产中包含未使用的组件:
// babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
env: {
production: {
plugins: ["react-native-paper/babel"],
},
},
};
};
然后导航到app/_layout.tsx,像这样用PaperProvider
封装应用程序:
// app/_layout.tsx
// ...
export default function RootLayout() {
// ...
return (
<ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
<PaperProvider>
<Stack>
<Stack.Screen name="index" options={{headerShown: false}}/>
<Stack.Screen name="(auth)" options={{headerShown: false}}/>
<Stack.Screen name="(tabs)" options={{headerShown: false}}/>
<Stack.Screen name="+not-found"/>
</Stack>
</PaperProvider>
</ThemeProvider>
);
}
不要忘记文件顶部的导入:
import {PaperProvider} from "react-native-paper";
很好,我们已经成功安装了组件库。
集装箱
我们要做的另一件事是创建一个容器
组件。这个组件将用于我们所有的屏幕,它将在所有边上添加一个边距,这样内容就不会超出屏幕边缘。
在组件文件夹中创建Container.tsx文件:
// components/Container.tsx
import React from "react";
import {View} from "react-native";
export type ContainerProps = {
children: React.ReactNode;
}
export function Container({children}: ContainerProps) {
return (
<View style={{margin: 12}}>
{children}
</View>
);
}
导航和屏幕
正如项目介绍中提到的,我们的应用程序将有两个导航选项卡。
一个是已通过身份验证的用户,另一个是未通过身份验证的用户。已通过身份验证的选项卡允许用户管理自己的配置文件,另一个选项卡则允许用户登录或创建账户。
为此,首先创建以下目录结构:
app/
├── (auth)/
│ ├── _layout.tsx
│ ├── login.tsx
│ └── register.tsx
├── (tabs)/
│ ├── _layout.tsx
│ └── profile.tsx
├── +html.tsx
├── +not-found.tsx
├── _layout.tsx
└── index.tsx
有关世博路由器的更多信息,请查看官方文档。
Expo 布局通常包含大量模板代码。我不想用代码淹没这篇文章,所以请从 GitHub 获取文件内容:
在index.tsx 中加入以下内容:
// app/index.tsx
import React, {useEffect} from "react";
import {ActivityIndicator} from "react-native-paper";
import {useRouter} from "expo-router";
import {View} from "react-native";
export default function IndexScreen() {
const router = useRouter();
const isAuthenticated = true;
useEffect(() => {
setTimeout(() => {
if (isAuthenticated) {
router.push("profile");
} else {
router.push("login");
}
}, 1000);
}, []);
return (
<View style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}>
<ActivityIndicator
size="large"
animating={true}
/>
</View>
);
}
index.tsx文件是应用程序的入口点。在该文件中,我们会检查用户是否已通过身份验证,然后对其进行相应的重定向。目前,重定向基于isAuthenticated
变量。
然后抓取屏幕的代码:
屏幕代码非常简单。它是 React Native 代码,使用 React Native Paper 创建表格和其他用户界面。它还使用了基本的 React 钩子,如useState()
和useEffect
()
。
Parse SDK
为了连接后台,我们将使用Parse SDK。SDK 提供了数据存储、操作、用户身份验证等方法。
首先,通过 NPM 安装:
$ npm install parse @react-native-async-storage/async-storage --save
$ npm install --save-dev @types/parse
我们还安装了@react-native-async-storage/async-storage
软件包,以便在应用程序关闭时持久化用户会话。如果没有它,用户每次打开应用程序时都必须进行身份验证。
然后像这样在项目根目录下创建一个.env文件:
EXPO_PUBLIC_APPLICATION_ID=<your-back4app-application-id>
EXPO_PUBLIC_JAVASCRIPT_KEY=<your-back4app-client-key>
确保更换
<your-back4app-application-id>
和<your-back4app-client-key>
替换为在文章后台部分获得的 API 密钥。
像这样在_layout.tsx中初始化 Parse:
// app/_layout.tsx
// ...
import Parse from "parse/react-native.js";
import AsyncStorage from "@react-native-async-storage/async-storage";
import ParseContext from "@/context/parseContext";
Parse.setAsyncStorage(AsyncStorage);
Parse.initialize(
process.env.EXPO_PUBLIC_APPLICATION_ID ?? "",
process.env.EXPO_PUBLIC_JAVASCRIPT_KEY ?? "",
)
Parse.serverURL = "https://parseapi.back4app.com/";
async function testParse() {
try {
const testMessage = new Parse.Object("TestMessage");
testMessage.set("message", "Hello, World!");
await testMessage.save();
} catch (error) {
console.log("Error saving the test message: ", error);
}
}
testParse().then(() => console.log("Successfully connected to Parse!"));
// ...
我们还加入了testParse()
函数,通过在数据库中添加 “Hello, world!”消息来测试与 Back4app 的连接。重启 Expo 服务器并在模拟器中运行应用程序,确保连接正常。
导航到应用程序的数据库视图,检查是否可以看到消息。
如果出现 “Error: crypto.getRandomValues() not supported”(错误:不支持 crypto.getRandomValues())的错误信息。安装以下依赖项:
npm install react-native-get-random-values --save
npm i --save-dev @types/react-native-get-random-values
然后在_layout.tsx的顶部(导入 Parse 之前)添加导入:
import "react-native-get-random-values";
重新启动开发服务器;一切都应该运行正常。
为了让 Parse 实例在所有屏幕上都可用,我们将使用 React Context 来传递它。
首先,创建一个上下文目录,并在其中放入以下parseContext.ts文件:
import {createContext} from "react";
const ParseContext = createContext<typeof Parse | null>(null);
export default ParseContext;
然后,在传递 Parse 实例的同时用它来封装整个应用程序:
// app/_layout.tsx
// ...
return (
<ParseContext.Provider value={Parse}>
{/* ... */}
</ParseContext.Provider>
)
数据检索与处理
在最后一部分,我们将使用 Parse SDK 验证用户身份并获取用户信息。
我们将创建一个useParse
钩子,而不是在每个屏幕中重复相同的代码。该钩子将从上下文中获取Parse
实例,获取用户信息,并在一切就绪后触发更新。
在上下文文件夹中新建一个名为useParse.ts 的文件:
// context/useParse.ts
import {useContext, useEffect, useState} from "react";
import ParseContext from "@/context/parseContext";
export function useParse() {
const parse = useContext(ParseContext) as typeof Parse;
const [parseUser, setParseUser] = useState<Parse.User | null>(null);
const [isParseLoaded, setIsParseLoaded] = useState(false);
useEffect(() => {
(async () => {
try {
setParseUser(await parse.User.currentAsync());
} catch (e) {
console.error(e);
} finally {
setIsParseLoaded(true);
}
})();
}, []);
return {parse, parseUser, isParseLoaded};
}
然后修改index.tsx,将isAuthenticated
替换为实际会话检查:
// app/index.tsx
// ...
import {useParse} from "@/hooks/useParse";
export default function IndexScreen() {
const router = useRouter();
const {parse, parseUser, isParseLoaded} = useParse();
useEffect(() => {
if (!isParseLoaded) return;
(async () => {
if (parseUser) {
console.log("User is authenticated!");
console.log(parseUser.toJSON());
router.replace("/profile");
} else {
console.log("User is not authenticated.");
console.log({});
router.replace("/(auth)/login");
}
})();
}, [isParseLoaded]);
return (
// ...
);
}
接下来,修改login.tsx以登录用户:
// app/(auth)/login.tsx
// ...
import {useParse} from "@/hooks/useParse";
export default function LoginScreen() {
const router = useRouter();
const {parse, parseUser, isParseLoaded} = useParse();
// ...
const onLogin = async () => {
// ...
try {
await parse.User.logIn(username, password);
router.push("/(tabs)/profile");
} catch (error: any) {
setError(error.message);
}
}
return (
// ...
);
}
然后修改 register.tsx类似login.tsx,但这次要像这样替换 TODO:
// app/(auth)/register.tsx
try {
const user = await parse.User.signUp(username, password, undefined, undefined);
user.setEmail(email);
await user.save();
router.replace("/(tabs)/profile")
} catch (error: any) {
setError(error.message);
}
最后修改profile.tsx,以显示配置文件信息:
// app/(tabs)/profile.tsx
// ...
import {useParse} from "@/hooks/useParse";
export default function IndexScreen() {
const router = useRouter();
const {parse, parseUser, isParseLoaded} = useParse();
// ...
useEffect(() => {
if (!parseUser) return;
setBio(parseUser.get("bio") || "");
}, [parseUser]);
const onSave = async () => {
if (!parseUser) return;
parseUser.set("bio", bio);
try {
await parseUser.save();
setSuccess("Bio saved successfully.");
} catch (error: any) {
setError(error.message);
}
}
const onLogout = async () => {
router.replace("/(auth)/login");
await parse.User.logOut();
}
return (
<Container>
{!isParseLoaded ? (
<ActivityIndicator
size="large"
animating={true}
/>
) : (
<>
{/* ... */}
</>
)}
</Container>
);
}
记住更改返回调用中的 TODO。使用{parseUser!.getUsername()}
和{parseUser
!.
getEmail
()}
。
此时,应用程序应已完全正常运行。重新启动开发服务器,并通过创建账户、登录、注销和更改个人资料进行测试。最后,确保更改已反映在数据库中。
结论
总之,你现在知道了什么是身份验证、它的好处以及它与授权的比较。
此外,您还学会了如何设置 Back4app 身份验证并将其与 React Native(基于 Expo)应用程序集成。
今后的步骤
- 了解Google、Facebook 和Apple的社交认证功能
- 查看Back4app 管理应用程序,获取高级实时管理面板
最终源代码可在GitHub 上获取。