使用 JWT 身份验证、MongoDB 和 Express.js 构建高级 CRUD API
为了在 Node.js 中构建更高级的 CRUD API,我们可以添加以下几个功能:
您可以按照以下方式实现此目的:
1. 设置项目并安装依赖项
创建新项目并安装必要的依赖项:
mkdir advanced-crud-api cd advanced-crud-api npm init -y
安装以下依赖项:
npm install express mongoose dotenv joi jsonwebtoken bcryptjs body-parser npm install --save-dev nodemon
2.创建环境配置
创建一个 `.env` 文件来存储敏感数据:
touch .env
在 `.env` 文件中添加以下配置:
PORT=5000 DB_URI=mongodb://localhost:27017/advanced-crud JWT_SECRET=your_jwt_secret_key
3.创建模型和数据库配置
创建一个 `models` 文件夹并在 `models/User.js` 中定义一个 `User` 模型:
const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ name: { type: String, required: [true, 'Name is required'], }, email: { type: String, required: [true, 'Email is required'], unique: true, match: [/^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/, 'Please provide a valid email'], }, password: { type: String, required: [true, 'Password is required'], minlength: [6, 'Password should be at least 6 characters long'], }, }); module.exports = mongoose.model('User', userSchema);
在这个模型中,我们包含了“姓名”、“电子邮件”和“密码”的验证规则。
4.数据库连接设置
创建一个 `config/db.js` 文件来设置数据库连接:
const mongoose = require('mongoose'); const dotenv = require('dotenv'); dotenv.config(); const connectDB = async () => { try { await mongoose.connect(process.env.DB_URI, { useNewUrlParser: true, useUnifiedTopology: true, }); console.log('MongoDB connected'); } catch (error) { console.error('Error connecting to MongoDB:', error.message); process.exit(1); // Exit process with failure } }; module.exports = connectDB;
5. JWT 身份验证辅助函数
创建一个文件 `utils/auth.js` 来处理 JWT 生成和密码哈希处理:
const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const generateToken = (id) => { return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: '30d' }); }; const hashPassword = async (password) => { const salt = await bcrypt.genSalt(10); return await bcrypt.hash(password, salt); }; const comparePasswords = async (password, hashedPassword) => { return await bcrypt.compare(password, hashedPassword); }; module.exports = { generateToken, hashPassword, comparePasswords };
6. 创建用于 CRUD 操作的控制器
在 `controllers` 文件夹中,创建 `userController.js` 来处理 CRUD 操作。
const User = require('../models/User'); const Joi = require('joi'); const { generateToken, hashPassword, comparePasswords } = require('../utils/auth'); // Validation schema const userValidationSchema = Joi.object({ name: Joi.string().min(3).required(), email: Joi.string().email().required(), password: Joi.string().min(6).required(), }); // Register user exports.registerUser = async (req, res) => { try { const { name, email, password } = req.body; // Validate input data const { error } = userValidationSchema.validate(req.body); if (error) return res.status(400).json({ error: error.details[0].message }); // Check if the user already exists const userExists = await User.findOne({ email }); if (userExists) { return res.status(400).json({ message: 'User already exists' }); } const hashedPassword = await hashPassword(password); const newUser = new User({ name, email, password: hashedPassword }); await newUser.save(); const token = generateToken(newUser._id); res.status(201).json({ user: newUser, token }); } catch (err) { res.status(500).json({ message: 'Server error' }); } }; // Login user exports.loginUser = async (req, res) => { try { const { email, password } = req.body; // Validate input data const { error } = userValidationSchema.validate(req.body); if (error) return res.status(400).json({ error: error.details[0].message }); const user = await User.findOne({ email }); if (!user) return res.status(400).json({ message: 'Invalid email or password' }); const isMatch = await comparePasswords(password, user.password); if (!isMatch) return res.status(400).json({ message: 'Invalid email or password' }); const token = generateToken(user._id); res.json({ user, token }); } catch (err) { res.status(500).json({ message: 'Server error' }); } }; // Get user details exports.getUserDetails = async (req, res) => { try { const user = await User.findById(req.user.id).select('-password'); if (!user) return res.status(404).json({ message: 'User not found' }); res.json(user); } catch (err) { res.status(500).json({ message: 'Server error' }); } }; // Update user details exports.updateUser = async (req, res) => { try { const { name, email } = req.body; const user = await User.findByIdAndUpdate(req.user.id, { name, email }, { new: true }); if (!user) return res.status(404).json({ message: 'User not found' }); res.json(user); } catch (err) { res.status(500).json({ message: 'Server error' }); } }; // Delete user exports.deleteUser = async (req, res) => { try { const user = await User.findByIdAndDelete(req.user.id); if (!user) return res.status(404).json({ message: 'User not found' }); res.status(204).send(); } catch (err) { res.status(500).json({ message: 'Server error' }); } };
7. 使用中间件保护路由
创建一个中间件“middleware/auth.js”来保护需要身份验证的路由:
const jwt = require('jsonwebtoken'); const protect = (req, res, next) => { const token = req.header('Authorization')?.replace('Bearer ', ''); if (!token) return res.status(401).json({ message: 'No token, authorization denied' }); try { const decoded = jwt.verify(token, process.env.JWT_SECRET); req.user = decoded; // Attach user info to request next(); } catch (err) { res.status(401).json({ message: 'Token is not valid' }); } }; module.exports = protect;
8. 设置快速路线
在 `routes/userRoutes.js` 中创建用户操作的路由:
const express = require('express'); const { registerUser, loginUser, getUserDetails, updateUser, deleteUser } = require('../controllers/userController'); const protect = require('../middleware/auth'); const router = express.Router(); router.post('/register', registerUser); router.post('/login', loginUser); router.get('/me', protect, getUserDetails); router.put('/me', protect, updateUser); router.delete('/me', protect, deleteUser); module.exports = router;
9. 设置主应用程序
现在,在“index.js”中设置主服务器文件:
const express = require('express'); const dotenv = require('dotenv'); const connectDB = require('./config/db'); const userRoutes = require('./routes/userRoutes'); dotenv.config(); const app = express(); // Connect to database connectDB(); app.use(express.json()); // Parse incoming JSON requests app.use('/api/users', userRoutes); // Use the user routes const PORT = process.env.PORT || 5000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
10.运行服务器
最后,启动
服务器:
npm run dev
您现在拥有一个功能齐全的高级 CRUD API,其中包含 JWT 身份验证、用户注册和错误处理。
结论
此高级设置涵盖: