在本文中,我们将从零开始创建一个 MERN 栈应用程序。此项目的视频可以在此处找到。前端将使用 React、Redux、React Router 和 React Bootstrap 构建单页面应用程序。后端将使用 Express、MongoDB 和 Mongoose 作为数据库,并使用 JWT(JSON Web Tokens)和 HTTP-only Cookie 来实现身份验证。我们还将使用 Redux 进行状态管理,并使用 Redux Toolkit 使事情变得更加简单。本文将分为两个部分。第一部分我们将创建后端,第二部分我们将创建前端。
本项目的主要焦点是设置身份验证。它将帮助你更好地理解在 API 中创建路由/控制器,以及在 React/Redux 中管理状态。
此项目的所有代码可以在此 GitHub 存储库中找到。
好了,让我们开始吧。
在我们开始之前,我只想提到,在 MERN 堆栈应用程序中,有很多实现身份验证的方法。有第三方服务,如 Auth0 和 Firebase,使其变得非常简单。还有许多不同的库和包可供使用,例如 Passport.js。我选择以这种方式进行,因为它非常简单,除了 jsonwebtokens 包之外,不需要任何第三方服务或库。这也是一个很好的学习经验。
这将按以下方式工作:我们将拥有一个用于身份验证和验证电子邮件和密码的路由。一旦验证通过,我们将创建一个 JSON Web Token,并将其作为 HTTP-only Cookie 发送回客户端。我们还将有一个用于注册用户的路由,一个用于获取用户配置文件的路由,以及一个用于更新用户配置文件的路由。我们还将有一个用于注销用户并清除 Cookie 的路由。
开始入门
和我做的大多数项目一样,我喜欢从头开始。我们将从后端开始,设置数据库并创建路由、模型和控制器。我们将创建一些身份验证中间件,最终的结果应该是一个完全功能的登录和注册功能,可以将 JWT 保存在 HTTP-only Cookie 中。完成后,我们可以转到前端并创建我们的 React 应用程序。
后端设置
让我们初始化一个新项目并安装我们的依赖项。我将创建一个名为 mern-auth
的新目录,然后运行 npm init -y
以使用默认设置初始化一个新项目。然后用 VS Code 打开它。
mkdir mern-auth
cd mern-auth
npm init -y
code .
所有服务器依赖项都将安装在此目录中。让我们安装 Express、Mongoose、bcryptjs、jsonwebtoken 和 cookie-parser。
npm i express dotenv mongoose bcryptjs jsonwebtoken cookie-parser
以下是这些软件包的简要说明:
- Express——用于 Node.js 的 Web 框架
- dotenv——从
.env
文件加载环境变量 - mongoose—— MongoDB 对象建模工具
- bcryptjs——用于散列和盐化用户密码的库
- jsonwebtoken——用于生成 JWT 的库
- cookie-parser——用于解析 Cookie 的中间件
我们将创建一个名为 backend
的目录,其中包含我们的服务器端代码。入口点将是 backend/server.js
。现在让我们创建它。
mkdir backend
touch backend/server.js
在 backend/server.js
中,让我们设置一个非常基本的 Express 服务器并运行它。
const express = require('express');
const port = 5000;
const app = express();
app.get('/', (req, res) => res.send('API running'));
app.listen(port, () => console.log(`Server started on port ${port})`));
我们可以使用 node backend/server.js
运行服务器,但我们想要使用 nodemon,这样每次我们进行更改时都不必重启服务器。让我们将其安装为开发依赖项。
npm i -D nodemon
现在,让我们在 package.json
文件中添加一些 NPM 脚本。
"scripts": {
"start": "node backend/server.js",
"server": "nodemon backend/server.js"
},
现在我们可以运行 npm run server
来启动服务器。我们应该在 http://localhost:5000
的浏览器中看到消息“API running”。在生产中将使用 npm start。
安装 Postman
我们将使用 Postman 来测试我们的 API。如果你没有安装它,请访问 https://www.postman.com/downloads 并下载适合你的操作系统的版本。
你可以通过在 Postman 中向 http://localhost:5000
发出 GET 请求来测试 API,你应该看到消息“API running”。
ES 模块
在我的 Node.js 项目中,我喜欢使用 ES 模块而不是 CommonJS。这是一种更易读、更易于使用的新语法。这也是我们将在前端 React 应用程序中使用的语法。要使用它,我们只需在 package.json
文件中添加以下内容。
"type": "module",
现在,将 server.js
中的 Express 导入更改为以下内容:
import express from 'express';
你的服务器应该仍然可以正常工作。
环境变量
我想创建一个文件来存储环境变量,它们基本上是我们不希望硬编码到代码中的变量。比如数据库凭据、API 密钥等。我们将使用 dotenv
包来实现这一点。
让我们在项目的根目录中创建一个名为 .env
的文件,并添加以下内容:
NODE_ENV=development
PORT=5000
你还应将此文件添加到 .gitignore
文件中,以防止其被推送到 GitHub。在根目录中创建一个名为 .gitignore
的文件,并添加以下内容:
node_modules
.env
现在,在 server.js
文件中,我们可以导入 dotenv
包并使用它来加载我们的环境变量。
import dotenv from 'dotenv';
dotenv.config();
现在更改端口以使用环境变量。
const port = process.env.PORT || 5000;
重新启动服务器,现在它应该使用.env 文件中的端口。你可以将数字更改为其他值进行测试。
用户路由和控制器
让我们设置我们的路由。我们将有以下路由:
- POST /api/users——注册用户
- POST /api/users/auth——验证用户并获取令牌
- POST /api/users/logout ——注销用户并清除 Cookie
- GET /api/users/profile—— 获取用户个人资料
- PUT /api/users/profile——更新个人资料
让我们首先在 backend
目录中创建一个名为 routes
的目录,然后在其中创建一个名为 userRoutes.js
的文件。这将包含我们的所有用户路由。
虽然我们可以在这个文件中拥有所有的路由逻辑,但最好将其分离到一个控制器中。让我们在 backend
目录中创建一个名为 controllers
的目录,然后在其中创建一个名为 userController.js
的文件。
让我们首先创建一个单个的控制器函数,并将其连接到一个路由,只是为了让代码跑起来。在 userController.js
中添加以下代码。
// @desc 验证用户并获取令牌
// @route POST /api/users/auth
// @access Public
const authUser = (req, res) => {
res.json({ message: 'Success' });
};
export { authUser };
我喜欢在每个控制器函数的顶部放置一条注释,描述它的功能、路由和访问级别。当然,这是可选的。
我们只是发送一个包含消息“Success”的 JSON 响应。现在,让我们将其连接到一个路由中。在 userRoutes.js
中添加以下代码。
import express from 'express';
const router = express.Router();
import { authUser } from '../controllers/userController.js';
router.route('/auth').post(authUser);
export default router;
我们正在从 userController.js
导入 authUser
函数,并将其连接到路由 POST /api/users/auth
。现在,让我们将其引入 server.js
并将其连接到 /api/users
路由。
import userRoutes from './routes/userRoutes.js';
app.use('/api/users', userRoutes);
测试路由
打开 Postman 或任何 HTTP 客户端,向 http://localhost:5000/api/users/auth
发出 POST 请求。你应该会看到带有消息“Success”的 JSON 响应。
使用异步处理程序
我们将在控制器函数中使用 async/await。我们可以在每个函数中使用 try/catch 块,但那样会很冗长。相反,我们将创建一个函数,它将包装每个控制器函数并处理任何错误。为了保持代码简单,我们将安装 express-async-handler
。
npm i express-async-handler
现在,将其引入 userController.js
,以便我们可以在函数中使用它。
import asyncHandler from 'express-async-handler';
现在,将 asyncHandler
添加到 authUser
函数中。
const authUser = asyncHandler(async (req, res) => {
res.json({ message: 'Success' });
});
这将允许我们在函数中使用 async/await,并且如果出现错误,它将被传递给我们的自定义错误处理程序,我们将在此处创建它。
自定义错误处理程序
在 backend
中创建一个名为 middleware
的文件夹,然后在其中创建一个名为 errorMiddleware.js
的文件。这将包含我们的自定义错误处理程序。
const notFound = (req, res, next) => {
const error = new Error(`Not Found - ${req.originalUrl}`);
res.status(404);
next(error);
};
const errorHandler = (err, req, res, next) => {
let statusCode = res.statusCode === 200 ? 500 : res.statusCode;
let message = err.message;
// If Mongoose not found error, set to 404 and change message
if (err.name === 'CastError' && err.kind === 'ObjectId') {
statusCode = 404;
message = 'Resource not found';
}
res.status(statusCode).json({
message: message,
stack: process.env.NODE_ENV === 'production' ? null : err.stack
});
};
export { notFound, errorHandler };
我们创建了两个中间件函数。第一个将用作捕获所有不存在的路由。第二个将用作捕获路由中发生的任何错误。
因此,这将允许我们从任何控制器函数中抛出错误,并将其传递给我们的自定义错误处理程序中间件,然后响应适当的状态码和消息。
我们还检查了一种特定类型的错误,即 Mongoose 的 CastError
。当将无效的 ID 传递给 Mongoose 查询时,将抛出此错误。我们进行了检查,如果出现该错误,我们将将状态码设置为 404,消息设置为“Resource not found”。
这段代码非常有用,我在大多数 Node 项目中都使用它。
现在,我们需要将这些函数引入 server.js
并使用它们。将以下内容添加到文件顶部。
import { notFound, errorHandler } from './middleware/errorMiddleware.js';
现在,在路由之后,将以下内容添加到文件底部。
app.use(notFound);
app.use(errorHandler);
添加其余路由
现在我们已经设置好错误处理程序,可以添加其余的控制器函数和路由。在userController.js
中添加以下代码。
import asyncHandler from 'express-async-handler';
// @desc 验证用户并获取令牌
// @route POST /api/users/auth
// @access public
const authUser = asyncHandler(async (req, res) => {
res.send('Auth User');
});
// @desc 注册用户
// @route POST /api/users
// @access public
const registerUser = asyncHandler(async (req, res) => {
res.send('register user');
});
// @desc 注销用户并清除 Cookie
// @route POST /api/users/logout
// @access private
const logoutUser = asyncHandler(async (req, res) => {
res.send('logout user');
});
// @desc 获取用户资料
// @route GET /api/users/profile
// @access private
const getUserProfile = asyncHandler(async (req, res) => {
res.send('get profile');
});
// @desc 更新用户资料
// @route PUT /api/users/profile
// @access private
const updateUserProfile = asyncHandler(async (req, res) => {
res.send('update profile');
});
目前我们只是发送一个字符串作为响应。稍后我们将添加实际的功能。
添加路由
现在所有的路由都应该工作,并且只会响应我们在控制器函数中添加的字符串。可以在 Postman 中进行测试。确保为每个路由选择正确的 HTTP 方法。
import express from 'express';
import {
authUser,
registerUser,
logoutUser,
getUserProfile,
updateUserProfile
} from '../controllers/userController.js';
const router = express.Router();
router.post('/', registerUser);
router.post('/auth', authUser);
router.post('/logout', logoutUser);
router.route('/profile').get(getUserProfile).put(updateUserProfile);
export default router;
数据库设置
现在我们将设置数据库。我们将使用 MongoDB Atlas,这是一个云数据库服务。你可以在本地安装 MongoDB,但我更喜欢 Atlas,因为它易于设置和使用。
创建 MongoDB Atlas 账户
访问MongoDB Atlas并点击“Start Free”按钮。按照步骤创建账户并确认你的电子邮件地址。
创建账户后,登录并创建一个数据库/集群。可能会要求你先创建一个组织和项目,如果是这样,请先进行创建并按你的要求进行命名。
然后应该会要求你创建一个数据库,界面如下所示:
接下来,你将看到一个询问你希望选择哪个计划的屏幕。
选择免费的 M0
计划。保留 AWS 作为提供商。如果需要,可以更改集群名称和区域。然后点击“create”。
现在将提示你创建一个数据库用户。这是我们将用来连接数据库的用户。一定要点击“Create User”按钮。
向下滚动并点击“Add My IP Address”。这将允许你从计算机连接到数据库。然后点击“Finish & Close”。
现在你在云端拥有一个部署好的数据库。
创建数据库
我们有了一个集群,现在让我们创建实际的存储集合的数据库。点击“Browse Collections”,然后点击“Add My Own Data”。
输入一个数据库名称。我将使用“mernauth”。然后添加一个名为“users”的集合。
你可以从这里管理数据,但我不建议这样做。相反,你可以使用 MongoDB Compass,这是一个桌面应用程序。
连接字符串
现在我们需要获取数据库的连接字符串。点击“Connect”按钮,然后选择“Connect Your Application”。
复制连接字符串:
现在,打开你的 .env`文件并添加以下行:
MONGO_URI=<你的连接字符串>
在连接字符串中需要更改几个内容。首先,用你为数据库用户创建的密码替换 <password>
。
在连接字符串中需要更改几个内容。首先,将 <password>
替换为你为数据库用户创建的密码。其次,你需要添加你的数据库名称。我使用的名称是“mernauth",因此我将将其添加到连接字符串的末尾。它应该如下所示:
mongodb+srv://brad123:brad123@tutorial-cluster.lh0tyop.mongodb.net/mernauth?retryWrites=true&w=majority
所以我的 .env
文件应该如下所示:
NODE_ENV=development
PORT=5000
MONGO_URI=mongodb+srv://brad123:brad123@tutorial-cluster.lh0tyop.mongodb.net/mernauth?retryWrites=true&w=majority
请记得将 .env
文件添加到你的 .gitignore
文件中,如果你还没有这样做的话。否则,你将与全球分享你的数据库密码。
连接到数据库
现在我们需要连接到数据库。我们将使用已经安装的 mongoose
来实现。创建一个名为“config”的新目录,并在其中添加一个名为 db.js
的文件。然后添加以下代码。
import mongoose from 'mongoose';
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI);
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
};
export default connectDB;
这是使用 mongoose
连接到 MongoDB 数据库的一种常见方式。我们使用异步函数,以便可以使用 await
等待连接完成。如果发生错误,我们希望退出进程。否则,我们将记录已连接的主机。
现在,我们可以在 server.js
中导入此文件并调用 connectDB
函数。
import connectDB from './config/db.js';
const port = process.env.PORT || 5000; // Run under this line...
connectDB();
当你运行服务器时,你应该会在控制台上看到“MongoDB Connected”的消息。
用户模型
使用 Mongoose,我们需要为数据中的所有资源创建一个模型,对于我们来说,只有用户模型。在后端目录中创建一个名为 models
的新目录,并添加一个名为 userModel.js
的文件。然后添加以下代码。
import mongoose from 'mongoose';
const userSchema = mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
const User = mongoose.model('User', userSchema);
export default User;
我们的用户模型非常简单。我们有一个名称、电子邮件和密码。我们还有用户创建和更新的时间戳。在电子商务课程中,我们有一个 isAdmin
字段,但在这里我们不需要。
注册路由
现在,我们已经连接到了数据库,并且有了一个用户模型,让我们开始编写我们的第一个路由/控制器函数,即注册用户的路由。打开 userController.js
并导入 User
模型。
import User from '../models/userModel.js';
然后在 registerUser
函数中添加以下内容。
const registerUser = asyncHandler(async (req, res) => {
const { name, email, password } = req.body;
const userExists = await User.findOne({ email });
if (userExists) {
res.status(400);
throw new Error('User already exists');
}
const user = await User.create({
name,
email,
password,
});
if (user) {
res.status(201).json({
_id: user._id,
name: user.name,
email: user.email,
});
} else {
res.status(400);
throw new Error('Invalid user data');
}
});
我们从请求体中获取名称、电子邮件和密码。然后我们检查是否已经存在具有该电子邮件的用户。如果存在,我们抛出一个错误。如果不存在,我们创建用户并返回用户数据。
请求体解析中间件
为了能够从请求体中获取数据,我们需要在 server.js
中添加一些中间件。在 routes
之前的 server.js
中添加以下代码。
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
密码哈希
现在,如果我们使用 Postman 发送电子邮件和密码的请求,它将以明文形式存储在数据库中。我们不希望这样。我们希望在将其存储到数据库之前对密码进行哈希处理。我们将使用 bcryptjs
包进行哈希处理。
我们有几种方法可以实现这一点。我们可以在此处的控制器中实现,但我更喜欢在模型中实现。因此,打开 userModel.js
并添加以下代码。
import bcrypt from 'bcryptjs';
然后将以下代码添加到 userSchema
。
// Encrypt password using bcrypt
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
这将在用户保存到数据库之前运行。我们创建一个 salt
,它是一串随机字符,然后我们使用 salt
对密码进行哈希处理。数字越大,密码的安全性越高,但哈希处理时间也越长。10 是一个不错的数字。
测试路由
打开 Postman,并向路由 http://localhost:5000/api/users
发送 POST 请求,并添加以下请求体数据:
{
"name": "John Doe",
"email": "john@email.com",
"password": "123456"
}
你应该收到一个 201 状态码和用户数据。
现在,我们可以注册用户并将哈希密码存储在数据库中。你可以通过登录到 Atlas 或 Compass 来检查数据库。
JSON Web Tokens
现在,我们只是获取到用户的数据。我们需要一种方法来进行身份验证和检查用户,以便保护特定的路由。我们将使用 JSON Web Tokens 来实现。如果你一直在跟随操作步骤,那么你应该已经安装了 jsonwebtoken
包。如果没有安装,请现在安装它。
npm install jsonwebtoken
我们需要生成一个新的令牌并将其保存在 HTTP-only Cookie 中。我们可以在此文件中完成,但是我们必须在登录路由中执行相同的操作,所以我将这个功能放在一个实用程序文件中。
在后端目录中创建一个名为 utils
的文件夹,并添加一个名为 generateToken.js
的文件。然后添加以下代码。
import jwt from 'jsonwebtoken';
const generateToken = (res, userId) => {
const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: '30d'
});
res.cookie('jwt', token, {
httpOnly: true,
secure: process.env.NODE_ENV !== 'development', // Use secure cookies in production
sameSite: 'strict', // Prevent CSRF attacks
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
});
};
export default generateToken;
我们使用 jwt.sign()
方法创建令牌。第一个参数是负载,即用户 ID。第二个参数是密钥,我们将在 .env
文件中添加。第三个参数是选项,即到期日期。我将其设置为 30 天,但你可能希望将其设置为较短的时间。然后,我们使用令牌设置 Cookie。
在你的 .env
文件中,添加以下内容:
JWT_SECRET=abc123
你的密钥可以是任意内容。
现在,让我们将实用程序文件引入控制器并使用它:
import generateToken from '../utils/generateToken.js';
然后在检查用户之后和发送响应之前立即调用它:
generateToken(res, user._id);
我们传入 res
和 user._id
,它们将添加到令牌的负载中。
尝试注册一个新用户。如果你正在使用 Compass 或 Atlas,请删除用户 john
并注册相同的用户或创建一个新用户。
注册后,你应该在响应头中以及在 Postman 中看到 Cookie。
现在,该令牌应该随每个请求一起发送。因此,我们需要一个中间件函数来检查令牌并解码以获取用户 ID。
在 middleware
文件夹中创建一个名为 authMiddleware.js
的新文件,并添加以下代码:
import jwt from 'jsonwebtoken';
import asyncHandler from 'express-async-handler';
import User from '../models/userModel.js';
const protect = asyncHandler(async (req, res, next) => {
let token;
token = req.cookies.jwt;
if (token) {
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findById(decoded.userId).select('-password');
next();
} catch (error) {
console.error(error);
res.status(401);
throw new Error('Not authorized, token failed');
}
} else {
res.status(401);
throw new Error('Not authorized, no token');
}
});
export { protect };
这里我们做的是从 Cookie 中获取令牌。然后我们检查是否存在令牌。如果存在,我们验证令牌并从负载中获取用户 ID。然后我们通过 ID 查找用户,并将用户附加到请求对象上。然后我们调用 next()
,继续下一个中间件函数。如果没有令牌,我们抛出一个错误。
Cookie Parser Middleware
这很重要。我们使用 req.cookies.jwt
来访问 Cookie。为了做到这一点,我们需要添加 cookie-parser
中间件。确保已安装它。如果尚未安装,请立即安装。
npm install cookie-parser
然后在 server.js
文件中引入并使用它:
import cookieParser from 'cookie-parser';
app.use(cookieParser());
现在,我们可以将 protect
中间件引入到我们的路由文件中,并用它来保护我们想要保护的路由。让我们保护获取个人资料和更新个人资料的路由。
打开 userRoutes.js
并添加以下代码:
import { protect } from '../middleware/authMiddleware.js';
然后将 protect
作为第一个参数添加到 getProfile
和 updateProfile
路由中。
router
.route('/profile')
.get(protect, getUserProfile)
.put(protect, updateUserProfile);
这样做的效果是,如果我们尝试在没有令牌的情况下访问这些路由,我们将收到一个错误。现在让我们测试一下。
现在我们有了 Cookie,这意味着我们可以在 Postman 中访问受保护的路由。请尝试向 http://localhost:5000/api/users/profile
发送一个 GET 请求。你应该收到字符串作为响应。
现在,进入浏览器,你没有 Cookie,在尝试访问相同的路由时,应该收到一个错误。
Auth 路由
现在我们可以保护路由并注册用户了。让我们来处理用于验证现有用户的路由/函数。
打开 userController.js
文件,进入 authUser
函数并添加以下代码:
const authUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user && (await user.matchPassword(password))) {
generateToken(res, user._id);
res.json({
_id: user._id,
name: user.name,
email: user.email
});
} else {
res.status(401);
throw new Error('Invalid email or password');
}
});
这与注册路由非常相似,只是我们不是将新用户添加到数据库中,而是检查用户是否存在以及密码是否匹配。如果是,则生成令牌并返回用户数据。
比较密码
请记住,数据库中的密码是经过哈希处理的,因此我们需要将哈希密码与用户在请求中发送的密码进行比较。我们使用了 user.matchPassword()
方法进行检查。我们需要在用户对象上创建该方法。我们可以在模型中完成。
打开 userModel.js
文件,并添加以下代码:
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
这是一个可以在用户对象上调用的方法。它接受用户在请求中发送的密码,并将其与数据库
中的哈希密码进行比较。它返回一个 Promise,所以我们需要使用 await
。
测试路由
现在,我们已经“登录”为 john 用户,因为我们设置了 Cookie/jwt
。我们可以在 Postman 中删除 Cookie,方法是点击“cookies”选项卡并删除“jwt”Cookie。现在我们本质上已经注销。如果尝试访问个人资料路由,你将收到一个错误。
现在让我们尝试登录。向 http://localhost:5000/api/users/auth
发送一个 POST 请求,使用你创建的任何用户。首先使用错误的密码。你应该收到一个错误。现在使用正确的密码。对于我来说,密码是:
{
"email": "john@email.com",
"password": "123456"
}
你应该收到用户数据和响应头中的 Cookie。
现在我们可以注册和登录了。现在让我们添加登出功能。
登出路由
我们已经在 userController.js
文件中有一个名为 logoutUser
的函数。在该函数中添加以下代码:
const logoutUser = (req, res) => {
res.cookie('jwt', '', {
httpOnly: true,
expires: new Date(0)
});
res.status(200).json({ message: 'Logged out successfully' });
};
这将清除 Cookie,并发送一条消息。尝试通过向 http://localhost:5000/api/users/logout
发送一个 POST 请求来测试它。你应该收到该消息,并且 Cookie 应该被清除。
获取用户个人资料路由
现在,我们已经设置了身份验证路由,让我们处理用户个人资料路由。
在 userController.js
文件的 getUserProfile
函数中添加以下代码:
const getUserProfile = asyncHandler(async (req, res) => {
if (req.user) {
res.json({
_id: req.user._id,
name: req.user.name,
email: req.user.email
});
} else {
res.status(404);
throw new Error('User not found');
}
});
由于该路由使用了 protect
中间件,我们可以在请求对象上访问用户对象。我们可以使用它从数据库中获取用户并发送回用户数据。
确保已登录,并向 http://localhost:5000/api/users/profile
发送一个 GET 请求。你应该收到用户数据。
更新用户个人资料路由
我们想要的最后一件事是使用户能够更新他们的个人资料。在 userController.js
文件的 updateUserProfile
函数中添加以下代码:
const updateUserProfile = asyncHandler(async (req, res) => {
const user = await User.findById(req.user._id);
if (user) {
user.name = req.body.name || user.name;
user.email = req.body.email || user.email;
if (req.body.password) {
user.password = req.body.password;
}
const updatedUser = await user.save();
res.json({
_id: updatedUser._id,
name: updatedUser.name,
email: updatedUser.email
});
} else {
res.status(404);
throw new Error('User not found');
}
});
我们从数据库中获取用户并更新名称和电子邮件。如果用户发送了新密码,我们也会更新密码。然后,我们保存用户并发送更新后的用户数据。
确保已登录,并向 http://localhost:5000/api/users/profile
发送一个 PUT 请求,包含以下数据:
{
"name": "John Update"
}
这应该更新你的用户的名称。
现在,你可以继续进行第二部分并实现前端部分。
评论 (0)