认证是每个涉及公共和私人页面的优秀应用程序的重要部分,因此了解如何实现它以及其执行流程非常重要。
在本文中,我将解释令牌身份验证是什么,身份验证流程如何工作,然后向你展示如何在React.js应用程序中设置基于令牌的身份验证。
本文将要求你具有React.js中使用的重要术语的基本知识,因此为了顺利跟随,你应该熟悉或至少具有自定义钩子的基本知识,如何在React.js中使用条件操作,以及如何使用内置的React.js钩子,例如useState钩子。
如果你想查看完整项目以了解它的感觉,可以克隆存储库这里,然后使用npm start
在你的计算机上运行它。请注意,你的服务器必须正在运行,因此你必须打开一个新终端并运行node server.js
来运行服务器并测试它。
本文将分为以下几个部分:
What Is Token-Based Authentication
How To Setup React.js Projects and Pages
Setting Up Application’s Server for Generating Token
How To Store User’s Token
Conclusion
什么是基于令牌的身份验证
基于令牌的身份验证是使用身份验证令牌安全地在应用程序和网站之间传输用户身份的过程。此过程使组织能够将更多效率添加到其身份验证流程中。
它只是一个生成加密且安全的安全令牌的过程,并允许用户在成功提交这些令牌后进行验证请求,这些令牌将被存储以进行进一步的身份验证。
良好的身份验证令牌应在指定时间后过期。将身份验证令牌保持活动状态时间过长可能会使应用程序容易受到攻击,因为劫持者可以利用此漏洞劫持用户会话。
从上面的简单定义中,你应该了解到基于令牌的身份验证具有五个执行步骤,它们是:
- 用户通过提供必要的登录凭据发出请求
- 处理此请求并验证它,授予用户访问令牌
- 然后提交访问令牌以授予用户访问会话。
- 重要的是将这些身份验证令牌存储在应用程序中以进行进一步身份验证,并且有许多方法可以做到这一点。我们将在本文后面的令牌存储部分中介绍此内容。
- 最后,为了保护应用程序的用户免受网络攻击,有必要为生成的令牌设置超时过期时间。
可以用于识别和授予用户访问设备或应用程序的五种主要类型的令牌。
这些令牌可以在物理设备和软件应用程序中使用,它们包括:
- 软件令牌
- 断开连接的令牌
- JSON Web令牌(JWT)
- 连接的令牌
- 无接触令牌
上述每种令牌都具有特定的用例。
通过这个,我相信你必须已经了解了令牌身份验证是什么。在接下来的几节中,你将学习如何在React.js应用程序中设置基于令牌的身份验证并保护应用程序中的私有页面。
如何设置React.js项目和页面
为了开始这个部分,我将设置我的React.js
项目并创建两个组件(HomePage
和Dashboard
)在不同的页面上,也称为路由。
在你想要React.js项目的项目目录中,运行以下命令:
这将设置一个React.js项目文件夹,其中包含运行所需的所有必要文件和文件夹。
在任何你想要使用的代码编辑器中打开你的React.js项目。我正在使用VS Code。
在App.js
文件中,编辑src文件夹中的文件,删除标题标记,以便你的App.js
文件看起来像这样:
你将在应用程序中安装一些软件包。首先,我使用tailwindcss为我的应用程序进行样式设置。如果你想使用它,可以通过以下过程快速安装并设置它:
在终端中运行以下命令。在导航到你刚创建的React.js项目之后,安装tailwindcss、postcss和autoprefixer在你的应用程序依赖项中,如下所示:
然后运行以下命令以生成tailwind.config.js
文件和postcss.config.js
文件:
通过将以下代码添加到module.exports
对象的content数组中来配置tailwind.config.js
文件。这是代码:
上面的代码将为你的模板文件配置路径。从上面的代码中可以看出,你要求tailwindcss在src
文件夹中具有.js
、.jsx
、.ts
和.tsx
扩展名的所有文件中执行。
使用此指令,你的tailwindcss样式将添加到这些文件中,并且你可以在那里使用它们。
最后,在React.js项目的index.css
文件中使用以下代码为每个应用程序层添加@tailwind
指令:
就是这样。这就是在你的应用程序中设置tailwindcss所需的全部内容。让我们继续添加其他依赖项。
你将为我们的应用程序添加路由机制,因此需要react-router-dom。你还需要cors来共享应用程序页面之间的信息,还需要express来为应用程序设置后端服务器应用程序。
运行以下命令以安装react-router-dom:
cors
和express
将作为开发依赖项安装,因此运行以下命令以安装它们:
你已经拥有了开始应用程序所需的一切,但在运行启动脚本之前,让我们为应用程序添加一些样式。
通过修改你的index.css
文件中的代码将应用程序的背景颜色变为黑色:
现在,运行启动脚本以在localhost:3000
上查看你的应用程序。现在,你应该看到完全黑色背景的应用程序。
在src
文件夹中,创建另一个名为Components
的文件夹。在Components
文件夹中,创建Homepage.jsx
和Dashboard.jsx
文件。
这些文件将分别包含我们的Homepage
和Dashboard
组件。
以下显示了所有代码以创建Homepage.jsx
,以便你可以创建一个Homepage
组件在浏览器中显示简单的Homepage
消息:
在Dashboard.jsx
文件中,添加以下代码以创建Dashboard
组件:
最后,将这些组件导入App.js
文件并将它们放在不同的页面上。导入 react-router-dom
中的 BrowserRouter
、Routes
和 Route
组件。使用它们将这些组件设置在不同的页面上,代码如下:
如果你访问 localhost:3000
,你应该看到 Homepage
组件。
如果你访问 localhost:3000/Dashboard
,你也应该看到 Dashboard
组件。
但是,目前你的 Dashboard
组件不是私有的,每个人都可以访问它。它需要是私有的。
为了让用户访问 Dashboard
页面,他们需要在登录表单中提供用户名和密码,该表单将发出请求以获取认证令牌。因此,你将创建一个 Login
组件来创建这个表单。
再次在应用程序的 src
文件夹内创建一个名为 Login 的文件夹。
虽然不是必须的,但是作为一个好的约定,将 Components
分组放在单独的文件夹中是很好的。因此,我们将具有相同功能的 Homepage
和 Dashboard
组件保存在同一个文件夹中。
在 Login
组件中,创建一个 Login.jsx
文件,在这个文件中创建一个 Login
组件,并使用下面的代码为登录表单设置样式:
在 Dashboard
组件中设置逻辑,当用户尝试在没有正确身份验证(生成令牌)的情况下访问 Dashboard
页面时,将向用户显示此登录表单。
在 Dashboard.jsx
文件中,从 React 中导入 useState
hook。这将用于存储生成的令牌,以便授予用户访问权限。
之后,使用一个条件语句来渲染 Login
表单,如果用户没有令牌,则渲染表单。
因此,将你的 Dashboard
组件修改为以下内容:
保存 Login.jsx
和 Dashboard.jsx
文件,打开浏览器,保持应用程序运行状态,并导航到 localhoast:3000/Dashboard
。你将看到登录表单,而不是 Dashboard
页面。
太好了!现在,你有了一个私有页面,受到登录表单的保护,但问题是你的登录表单还没有起作用。这是因为你还没有为经过身份验证的用户生成令牌。
但是,你已经成功完成了使用令牌进行身份验证的第一步,即为用户提供在登录表单上发出请求的平台。
在下一部分中,你将创建一个后端服务器,该服务器将创建并向经过身份验证的用户发送生成的令牌。
设置用于生成令牌的应用程序服务器
从前面的部分,你在应用程序中创建了一个受登录页面保护的私有页面。
在本节中,你将在项目目录的根目录中创建一个 server.js
文件。
在这个文件中,你将使用 express 和 cors 创建一个服务器应用程序,该应用程序将向你的前端应用程序发送令牌并在用户使用登录表单发出请求时授予访问权限。
因此,在项目目录的根目录中创建一个 server.js
文件。在创建 server.js
文件后,你的项目文件夹结构应该如下所示:
在这个 server.js
文件中,添加下面的代码来创建服务器应用程序:
在上面的代码中,你完成了以下操作:
- 在第 1 行中导入或需要
express
,并将其传递到名为express
的变量中。 - 在第 2 行中,你需要
cors
并将其传递到cors
变量中。 - 在第 4 行中,你创建了一个名为
app
的变量,并将express
变量传递给它。 - 在第 5 行中,你要求你的服务器应用程序通过将
cors
作为参数传递给app.use()
方法来使用cors
包。 - 从第 7 行到第 11 行,你使用服务器应用程序向你的应用程序的登录路由发送了一个请求以发送一个令牌对象。
- 在第 13 行中,你要求应用程序监听
端口 8080
,并在运行服务器应用程序时将“API is running onlocalhost:8080/login
”消息发送到控制台。
为了查看这是否真的有效,请在 VS Code 中打开另一个终端,并运行 node server.js
。你应该直接在终端中看到“API is running on localhost:8080/login
”。
太好了,你有一个运行中的服务器。
你需要让你的 Login
组件发出请求,从你刚刚创建的后端服务器应用程序中获取此令牌。
为此,在 Login
组件中添加一个 PropType
,并在 Login
组件中解构你从 Dashboard
组件传递的 setToken
属性。然后,提取 setToken
属性。因此,将你的 Login.jsx
文件修改为以下内容:
创建一个函数,该函数将通过 POST 请求调用 fetch 方法,以提供凭据作为参数,并向服务器应用程序发出 POST 请求。
这将是一个 async
函数,它将采用凭据作为其参数,然后使用 POST 请求调用 fetch 方法。
因此,在所有导入之后,添加以下代码以创建 async
函数:
最后,你将创建两个状态:一个将保存用户名值,另一个将保存密码值。还需要添加一个 handleSubmit
函数,该函数将调用你刚刚创建的 LoginUser
函数,设置用户令牌,并在登录表单的每个字段上添加 onChange
事件。之后,你的应用程序将能够接收用户的输入。
将你的登录表单修改为以下内容:
整个 Login
组件的代码应该如下所示:
保存文件,回到浏览器,并保持服务器应用程序运行状态。输入一些登录凭据,然后你应该被导航到 Dashboard
组件。
我们将令牌存储在应用程序的本地状态变量中,但这会带来一个问题。现在,每次刷新页面或打开新选项卡时,我们的应用程序都会向用户呈现登录表单。
根据应用程序的要求,这可能不是一个好的解决方案。为解决这个问题,我们可以将令牌存储在 localStorage
或 sessionStorage
中。这样,即使用户刷新页面或打开新选项卡,他们也将保持登录状态。
尽管将令牌存储在本地和会话存储中具有不同的安全性问题,但我仍将向你展示如何在其中存储令牌,并在下一节中解释它们的安全性风险。
如何存储用户令牌
你创建了一个可用的登录表单,但目前,你的应用程序无法长时间保存用户的会话。因此,如果用户刷新页面或在会话中打开新标签,会话将结束,用户将不得不再次提供他们的凭据。
虽然你现在正在本地状态变量中存储用户的令牌,但你也可以将令牌存储在会话存储中,以使用户能够保持登录状态。或者你可以决定将其存储在本地存储中。
但是,在本地存储中存储也有其缺点,因为它会一直让用户保持登录状态,直到令牌从本地存储中取走。
因此,让我向你展示如何同时将用户的令牌存储在会话和本地存储中。
会话存储
要使用会话存储,请删除仪表板页面中的令牌状态并创建 setToken
和 getToken
函数。然后,将 getToken
函数分配给一个令牌变量。
因此,你的仪表板组件代码应该如下所示:
你将使用 setToken
函数将用户生成的令牌保存到会话中。为此,你将使用 setItem
方法。setItem
方法接受两个参数:一个键和一个字符串值。
因此,如果你要使用 setItem
方法设置用户令牌,那么你必须使用 JSON.stringify
方法将令牌从 JSON 对象转换为字符串。
使用以下代码调用 setItem
方法并将令牌保存在会话中:
通过这样做,你已成功地将用户的令牌保存在应用程序的会话存储中。但你仍然需要从会话存储中检索此令牌并将其存储在你的应用程序中,以便你的应用程序可以使用它来呈现所需的页面给用户。
你可以使用 getItem
方法从会话存储中获取令牌。getItem
方法只需要一个键值作为其参数,然后返回一个字符串值。
因此,在 getToken
函数中,添加 getItem
方法并使用以下代码从会话存储中检索用户令牌:
但现在,当成功检索到令牌时,你需要通知你的应用程序。这使得即使提供了凭据,用户也无法登录。
为此,创建一个自定义 hook,其中包含一个令牌状态和 setToken
函数,当成功检索到令牌时,它将触发应用程序的重新渲染。
创建一个新文件夹,并将其命名为 App
。在 App
文件夹内,创建一个名为 useToken
的新文件。
要创建自定义 hook,你必须使用前缀 *use
,这就是为什么我们使用 useToken
的原因。
在 useToken
文件中,导入 useState
并创建一个令牌状态和 setToken
函数。接下来,复制并粘贴 getToken
函数到 useToken
文件中,并将其更改为箭头函数。
此外,从 Dashboard
组件中复制 setToken
函数,并将名称更改为 saveToken
,因为你已经有一个名为 setToken
的函数,负责设置应用程序的令牌值。
因此,你的 useToken
代码应该如下所示:
最后,在 Dashboard
组件中导入并使用 useToken
hook。
由于你不再将令牌存储在本地状态变量中,因此不需要 useState
hook。你也不需要 setToken
和 getToken
函数,因为你已经在 useToken
hook 中拥有它们。
因此,清除它们并在 Dashboard
组件中添加 useToken
hook,使用以下代码:
保存文件,并再次使用仍在运行的服务器应用程序打开浏览器。你应该看到登录表单,并且这次它应该正常工作。
如果你打开一个新标签或刷新页面,你仍将登录到应用程序并保持在 Dashboard
页面上。
在应用程序中将会话令牌存储在本地存储之外的安全风险是,如果应用程序遭到攻击成功,它会将这些令牌暴露给恶意用户。此外,你需要实现一种自动结束用户会话的方式,以避免会话劫持。
下一个存储方法是使用本地存储。此方法遵循与会话存储相同的方法。
你只需要将自定义 hook 中的每个会话存储实例更改为 localStorage
。
如果你使用 localStorage
,则用户将永久登录到应用程序中,即使你结束应用程序,你仍将登录,直到直接从 localStorage
清除令牌。
因此,这些是存储用户生成的令牌的方法以及实现基于令牌的身份验证在应用程序中所采取的步骤。
结论
身份验证在保护 Web 应用程序用户免受攻击方面发挥着非常重要的作用。实施适当的身份验证对于将私有页面保持私有对于公众来说是很重要的。
在本文中,我介绍了如何在 React 应用程序中使用令牌来授予用户访问权限。我还向你展示了如何设置私有页面,并仅在进行适当身份验证和令牌发行后显示它们。
评论(0)