假设您正在构建一个即将启动的 Web 应用程序。您精心设计了用户界面,添加了令人兴奋的功能,并确保一切顺利运行。但随着发布日期的临近,一个挥之不去的问题开始让你担心——安全性。具体来说,如何确保只有正确的用户才能访问应用程序的正确部分。这就是身份验证的用武之地。
身份验证是验证用户身份的过程,是 Web 开发的一个关键方面。在广阔的数字环境中,确保用户可以安全地登录和注销您的应用程序至关重要。一不小心,您的应用程序就可能容易受到攻击,从而使用户数据面临风险。
在本文中,我们将探索 Node.js 中的安全身份验证,使用 bcrypt.js 哈希密码和 JWT 令牌来管理用户会话。最后,您将深入了解如何实施强大的登录/注销系统,确保用户数据的安全。
所以,让我们踏上构建防弹身份验证系统的旅程,从设置我们的环境到使用 JWT 保护我们的路由。准备好锁定您的 Node.js 应用程序了吗?让我们开始吧。
首先,使用 npm init -y 初始化 Node.js 项目,这会创建一个具有默认设置的 package.json 文件。接下来,安装必要的软件包:用于设置服务器的express、用于管理MongoDB的mongoose、用于处理JWT令牌的jsonwebtoken、用于散列密码的bcryptjs、用于环境变量的dotenv、用于启用跨域资源共享的cors、用于解析cookie的cookie-parser。最后,添加nodemon作为开发依赖,以便在代码更改时自动重启服务器。
1.`npm init -y` 2.`npm install express mongoose jsonwebtoken bcryptjs dotenv cors cookie-parser` 3.`npm install nodemon -D`
现在修改package.json文件。添加像我的代码和类型这样的脚本。
"scripts": { "dev": "nodemon backend/index.js", "start": "node backend/index.js" }, "type": "module",
接下来,我们将设置一个基本的 Express 服务器。创建一个名为 index.js 的文件。此代码初始化 Express 并创建应用程序的实例。然后,我们将为根 URL (“/”) 定义一个路由来处理传入的 HTTP GET 请求。之后,我们将在端口 8000 上启动服务器,使其能够侦听传入请求。
import express from "express"; const app = express(); app.get("/", (req, res) => { res.send("Server is ready"); }); app.listen(8000, () => { console.log("Server is running on PORT 8000"); });
现在,我们将创建一个名为“routes”的文件夹,并在该文件夹中创建一个名为 authRoute.js 的新文件,并粘贴以下代码以查看路由的基础知识。
在此代码片段中,我们使用 Express 设置不同身份验证端点的路由。首先,我们导入express库并创建一个新的路由器实例。然后,我们定义三个 GET 路由:/signup、/login 和 /logout,每个路由都使用一个 JSON 对象进行响应,指示相应的端点已被命中。最后,我们将路由器实例导出为默认导出,使其可用于应用程序的其他部分。
1.`npm init -y` 2.`npm install express mongoose jsonwebtoken bcryptjs dotenv cors cookie-parser` 3.`npm install nodemon -D`
现在更改 index.js 添加身份验证路由来测试您的端点。
"scripts": { "dev": "nodemon backend/index.js", "start": "node backend/index.js" }, "type": "module",
现在,您可以在浏览器中测试它......但为了方便起见,我将使用 Postman。您可以像这样测试所有端点。
类似地,您可以看到其他路线,例如注销和注册。
所以,我们的基本应用程序已准备就绪......现在使其成为一个强大且正确的身份验证系统。
现在,首先准备好我们的 mongoDB 数据库。为此,创建一个文件夹 Model,并在该文件夹下创建一个文件 User.js,并在此文件中为 mongoDB 数据库中的用户添加 Mongoose 架构和模型。该架构包括用户名、全名、密码和电子邮件字段,每个字段都具有指定的数据类型和约束,例如唯一性和所需状态。密码字段的最小长度也为 6 个字符。
import express from "express"; const app = express(); app.get("/", (req, res) => { res.send("Server is ready"); }); app.listen(8000, () => { console.log("Server is running on PORT 8000"); });
现在让我们连接到我们的数据库。我们将创建一个名为 db 的文件夹,并在其中创建一个名为 connectDB.js 的文件。在此文件中,我们将定义一个异步函数 connectMongoDB,它尝试使用 Mongoose 连接到 MongoDB 数据库。它从 MONGO_URI 环境变量获取数据库连接字符串。如果连接成功,它将记录一条包含主机名的成功消息。如果失败,它会记录错误并以状态代码 1 退出进程。该函数将被导出以供应用程序的其他部分使用。
import express from "express"; // Create a new Express router instance const router = express.Router(); // Define a GET route for the signup endpoint router.get("/signup", (req, res) => { // Return a JSON response indicating that the signup endpoint was hit res.json({ data: "You hit signup endpoint", }); }); // Define a GET route for the login endpoint router.get("/login", (req, res) => { // Return a JSON response indicating that the login endpoint was hit res.json({ data: "You hit login endpoint", }); }); // Define a GET route for the logout endpoint router.get("/logout", (req, res) => { // Return a JSON response indicating that the logout endpoint was hit res.json({ data: "You hit logout endpoint", }); }); // Export the router instance as the default export export default router;
现在要使用 MONGO_URI,我们必须将其放入 .env 文件中。这里我使用了本地 mongoDB 设置连接字符串。如果你愿意,你也可以使用 mongoDB atlas。
import express from "express"; import authRoute from "./routes/authRoutes.js"; const app = express(); app.get("/", (req, res) => { res.send("Server is ready"); }); app.use("/api/auth", authRoute); app.listen(8000, () => { console.log("Server is running on PORT 8000"); });
现在实现注册功能。对于这第一个,创建一个文件夹控制器和文件 authController.js
import mongoose from "mongoose"; // Define the User schema with various fields and their data types const userSchema = new mongoose.Schema( { // The unique username of the user username: { type: String, required: true, unique: true, }, fullName: { type: String, required: true, }, // The password of the user (min length: 6) password: { type: String, required: true, minLength: 6, }, // The email of the user (unique) email: { type: String, required: true, unique: true, }, }, { timestamps: true } ); // Create the User model based on the userSchema const User = mongoose.model("User", userSchema); // Export the User model export default User;
首先,它从请求正文中提取全名、用户名、电子邮件和密码。它使用正则表达式验证电子邮件格式,如果格式无效,则返回 400 状态。
接下来,该函数检查用户名或电子邮件是否已存在于数据库中。如果采取任一操作,则会返回带有错误消息的 400 状态。它还确保密码长度至少为 6 个字符,如果不满足此条件,则会发送另一个 400 状态。
然后使用 bcrypt 对密码进行安全哈希处理。使用提供的数据创建一个新的 User 实例并将其保存到数据库中。
保存后,该函数会生成一个 JWT 令牌,将其设置为 cookie,并返回 201 状态以及用户的 ID、全名、用户名和电子邮件。如果发生任何错误,则会将其记录下来,并发送 500 状态和“内部服务器错误”消息。
要激活此功能,您必须导入这些
1.`npm init -y` 2.`npm install express mongoose jsonwebtoken bcryptjs dotenv cors cookie-parser` 3.`npm install nodemon -D`
注意到什么了吗?一个名为 generateTokenAndSetCookie 的新东西...让我们看看它的代码...创建一个文件夹 utils,其中包含generateTokenAndSetCookie.js。
"scripts": { "dev": "nodemon backend/index.js", "start": "node backend/index.js" }, "type": "module",
**generateTokenAndSetCookie **函数创建一个 JWT 并将其存储在 cookie 中以用于用户身份验证。
JWT 一代:
该函数使用 jsonwebtoken 库创建 JWT。它使用用户的 ID 和密钥(来自环境变量的 JWT_SECRET)对令牌进行签名,并将其设置为在 15 天后过期。
设置 Cookie:
然后该令牌将存储在用户浏览器上的 cookie 中。 cookie 配置了几个安全属性:
因此该函数可确保用户会话的安全性和持久性,使其成为身份验证过程的关键部分。
这里我们必须在.env中添加另一个环境变量JWT_SECRET。您可以像这样添加任何类型的数字和字符串混合。
import express from "express"; const app = express(); app.get("/", (req, res) => { res.send("Server is ready"); }); app.listen(8000, () => { console.log("Server is running on PORT 8000"); });
现在我们的注册功能已经完成..所以现在就开始它的路线。
import express from "express"; // Create a new Express router instance const router = express.Router(); // Define a GET route for the signup endpoint router.get("/signup", (req, res) => { // Return a JSON response indicating that the signup endpoint was hit res.json({ data: "You hit signup endpoint", }); }); // Define a GET route for the login endpoint router.get("/login", (req, res) => { // Return a JSON response indicating that the login endpoint was hit res.json({ data: "You hit login endpoint", }); }); // Define a GET route for the logout endpoint router.get("/logout", (req, res) => { // Return a JSON response indicating that the logout endpoint was hit res.json({ data: "You hit logout endpoint", }); }); // Export the router instance as the default export export default router;
好的,现在让我们修改我们的index.js,在这里我们添加了一些新的导入。 dotenv: 从 .env 安全地加载环境变量; express.json(): 解析传入的 JSON 请求; express.urlencoded({ Extended: true }): 解析 URL 编码数据; cookieParser: 处理 JWT 令牌的 cookie; connectMongoDB(): 连接MongoDB进行数据存储; 路由: /api/auth 管理注册、登录和注销。
这里是index.js的更新代码
1.`npm init -y` 2.`npm install express mongoose jsonwebtoken bcryptjs dotenv cors cookie-parser` 3.`npm install nodemon -D`
所以。现在是时候在 Postman 中测试我们的注册功能了。让我们看看它是否有效。
所以,这是结果。
在这里你可以看到它工作正常,你也可以检查你的 mongoDB 数据库。
现在制作登录功能。让我们再次回到我们的 authController.js 文件
"scripts": { "dev": "nodemon backend/index.js", "start": "node backend/index.js" }, "type": "module",
登录控制器通过验证用户名和密码来验证用户身份。它首先使用用户名在数据库中搜索用户。如果找到,它会使用 bcrypt 将提供的密码与存储在数据库中的散列密码进行比较。如果用户名或密码不正确,则返回错误响应。验证成功后,它会生成一个 JWT 令牌,使用generateTokenAndSetCookie 将其设置为 cookie,并返回一条成功消息,表明用户已成功登录。
让我们在 authRoutes.js 中添加登录路由
import express from "express"; const app = express(); app.get("/", (req, res) => { res.send("Server is ready"); }); app.listen(8000, () => { console.log("Server is running on PORT 8000"); });
让我们在 Postman 中测试一下。
这里可以看到已经成功显示登录了。
好的。现在是最后一个功能,即注销功能。让我们来实现这个。很简单。
import express from "express"; // Create a new Express router instance const router = express.Router(); // Define a GET route for the signup endpoint router.get("/signup", (req, res) => { // Return a JSON response indicating that the signup endpoint was hit res.json({ data: "You hit signup endpoint", }); }); // Define a GET route for the login endpoint router.get("/login", (req, res) => { // Return a JSON response indicating that the login endpoint was hit res.json({ data: "You hit login endpoint", }); }); // Define a GET route for the logout endpoint router.get("/logout", (req, res) => { // Return a JSON response indicating that the logout endpoint was hit res.json({ data: "You hit logout endpoint", }); }); // Export the router instance as the default export export default router;
注销控制器通过使用 res.cookie 从客户端浏览器清除 JWT cookie,将其值设置为空字符串并将 maxAge 设置为 0,确保立即过期,从而安全地注销用户。成功清除 cookie 后,它会发送成功响应,并显示一条消息,指示用户已成功注销。如果在此过程中发生任何错误,它会捕获错误、记录错误并返回内部服务器错误响应。
将此路由添加到我们的 authRoute.js
import express from "express"; import authRoute from "./routes/authRoutes.js"; const app = express(); app.get("/", (req, res) => { res.send("Server is ready"); }); app.use("/api/auth", authRoute); app.listen(8000, () => { console.log("Server is running on PORT 8000"); });
好的。让我们测试一下我们的最后一个功能,看看它是否工作正常。
哦!…运行得非常好。 ??
所以,现在我们完整的身份验证后端已准备就绪。 ??
如果您不想自己编写所有代码并想要一个快速解决方案,我创建了一个名为 auth0_package 的 npm 包。你可以从这里获取。
您可以在此处的 github 存储库中获取我的上述所有代码。
现在您的后端应用程序已完成。在下一篇博客中,我将解释如何将其与您的前端集成。所以请继续关注??.
总之,在 Node.js 应用程序中实现安全身份验证对于保护用户数据并确保只有授权用户才能访问应用程序的特定部分至关重要。通过使用 bcrypt.js 进行密码哈希处理并使用 JWT 令牌进行会话管理,您可以创建一个强大的登录/注销系统。这种方法不仅增强了安全性,而且提供了无缝的用户体验。设置 MongoDB 数据库并使用 Express 进行路由进一步增强了后端基础设施。借助这些工具和技术,您可以放心地启动您的 Web 应用程序,因为您知道它受到了很好的保护,可以防止未经授权的访问和潜在的安全威胁。
以上是掌握 Node.js 中的安全身份验证:使用 bcrypt.js 和 JWT 登录/注销的详细内容。更多信息请关注PHP中文网其他相关文章!