简介:本文详细讲解Node.js环境下登录接口与注册接口的实现,涵盖密码加密、JWT令牌、接口安全、错误处理等核心环节,提供完整代码示例与最佳实践。
在Web开发中,用户认证系统是任何应用的基础模块。本章将深入探讨如何使用Node.js构建安全可靠的登录接口和注册接口,涵盖从密码加密到JWT令牌生成的完整流程。
mkdir auth-systemcd auth-systemnpm init -ynpm install express mongoose bcryptjs jsonwebtoken cors dotenv
// app.jsconst express = require('express');const cors = require('cors');require('dotenv').config();const app = express();app.use(cors());app.use(express.json());// 路由引入const authRoutes = require('./routes/authRoutes');app.use('/api/auth', authRoutes);const PORT = process.env.PORT || 5000;app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
// models/User.jsconst mongoose = require('mongoose');const bcrypt = require('bcryptjs');const userSchema = new mongoose.Schema({username: { type: String, required: true, unique: true },email: { type: String, required: true, unique: true },password: { type: String, required: true },createdAt: { type: Date, default: Date.now }});// 密码加密中间件userSchema.pre('save', async function(next) {if (!this.isModified('password')) return next();const salt = await bcrypt.genSalt(10);this.password = await bcrypt.hash(this.password, salt);next();});module.exports = mongoose.model('User', userSchema);
关键点说明:
bcryptjs进行密码哈希处理pre('save')中间件确保密码在保存前自动加密unique约束防止重复注册
// routes/authRoutes.jsconst express = require('express');const router = express.Router();const { registerUser } = require('../controllers/authController');router.post('/register', registerUser);module.exports = router;
// controllers/authController.jsconst User = require('../models/User');const registerUser = async (req, res) => {try {const { username, email, password } = req.body;// 验证输入if (!username || !email || !password) {return res.status(400).json({ msg: '请提供所有字段' });}// 检查用户是否存在const userExists = await User.findOne({ email });if (userExists) {return res.status(400).json({ msg: '用户已存在' });}// 创建新用户const user = new User({ username, email, password });await user.save();res.status(201).json({ msg: '用户注册成功' });} catch (err) {console.error(err);res.status(500).json({ msg: '服务器错误' });}};
安全注意事项:
// 继续authController.jsconst bcrypt = require('bcryptjs');const jwt = require('jsonwebtoken');const loginUser = async (req, res) => {try {const { email, password } = req.body;// 验证输入if (!email || !password) {return res.status(400).json({ msg: '请提供邮箱和密码' });}// 检查用户是否存在const user = await User.findOne({ email });if (!user) {return res.status(404).json({ msg: '用户不存在' });}// 验证密码const isMatch = await bcrypt.compare(password, user.password);if (!isMatch) {return res.status(400).json({ msg: '密码错误' });}// 生成JWT令牌const payload = {user: {id: user.id}};jwt.sign(payload,process.env.JWT_SECRET,{ expiresIn: '1h' },(err, token) => {if (err) throw err;res.json({ token });});} catch (err) {console.error(err);res.status(500).json({ msg: '服务器错误' });}};
在.env文件中添加:
JWT_SECRET=your_secret_key_here
JWT最佳实践:
// middleware/validator.jsconst { body, validationResult } = require('express-validator');exports.validateRegister = [body('username').isLength({ min: 3 }).withMessage('用户名至少3个字符'),body('email').isEmail().withMessage('请输入有效邮箱'),body('password').isLength({ min: 6 }).withMessage('密码至少6个字符'),(req, res, next) => {const errors = validationResult(req);if (!errors.isEmpty()) {return res.status(400).json({ errors: errors.array() });}next();}];
npm install express-rate-limit
// middleware/rateLimiter.jsconst rateLimit = require('express-rate-limit');const limiter = rateLimit({windowMs: 15 * 60 * 1000, // 15分钟max: 100 // 每个IP限制100个请求});module.exports = limiter;
/api/auth/registerraw和JSON
{"username": "testuser","email": "test@example.com","password": "test123"}
/api/auth/login
// 添加到authController.jsconst crypto = require('crypto');const sendEmail = require('../utils/sendEmail');const forgotPassword = async (req, res) => {const { email } = req.body;const user = await User.findOne({ email });if (!user) {return res.status(404).json({ msg: '用户不存在' });}// 生成重置令牌const resetToken = user.getResetPasswordToken();await user.save();// 创建重置URLconst resetUrl = `http://localhost:3000/resetpassword/${resetToken}`;// 发送邮件const message = `<h1>密码重置</h1><p>请点击以下链接重置密码:</p><a href="${resetUrl}">${resetUrl}</a>`;try {await sendEmail({to: user.email,subject: '密码重置令牌',text: message});res.json({ msg: '重置邮件已发送' });} catch (err) {console.error(err);user.resetPasswordToken = undefined;user.resetPasswordExpire = undefined;await user.save();return res.status(500).json({ msg: '邮件发送失败' });}};
// middleware/auth.jsconst jwt = require('jsonwebtoken');module.exports = function(req, res, next) {// 从header获取tokenconst token = req.header('x-auth-token');// 检查token是否存在if (!token) {return res.status(401).json({ msg: '无权限访问' });}try {// 验证tokenconst decoded = jwt.verify(token, process.env.JWT_SECRET);// 将用户信息添加到请求对象req.user = decoded.user;next();} catch (err) {res.status(401).json({ msg: '令牌无效' });}};
本章详细介绍了Node.js环境下登录接口和注册接口的完整实现流程,从基础环境搭建到安全增强措施,提供了可直接应用于生产环境的代码示例。开发者应根据实际项目需求调整实现细节,并始终遵循安全最佳实践。