Node.js + Express + MySQL:快速搭建用户认证系统

195 阅读4分钟

在当今的Web开发领域,Node.js因其高效和非阻塞I/O模型而广受欢迎。结合Express框架和MySQL数据库,我们可以快速构建一个完整的后端服务。本文将带你一步步实现一个简单的用户注册和登录系统。

一、环境准备

首先,确保你已经安装了Node.js和MySQL。然后创建一个新项目:

mkdir node-auth-system
cd node-auth-system
npm init -y

安装必要的依赖:

npm install express mysql2 body-parser bcryptjs jsonwebtoken cors
  • express: Node.js的Web框架

  • mysql2: MySQL数据库驱动

  • body-parser: 解析请求体

  • bcryptjs: 密码加密

  • jsonwebtoken: 生成JWT令牌

  • cors: 处理跨域请求

二、项目结构

node-auth-system/
├── config/
│   └── db.js          # 数据库配置
├── controllers/
│   ├── auth.js        # 认证逻辑
├── models/
│   └── user.js        # 用户模型
├── routes/
│   └── auth.js        # 认证路由
├── app.js             # 主应用文件
└── package.json

三、数据库配置

首先在MySQL中创建数据库和用户表:

CREATE DATABASE auth_system;
USE auth_system;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(50) NOT NULL UNIQUE,
  email VARCHAR(100) NOT NULL UNIQUE,
  password VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

然后在config/db.js中配置数据库连接:

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'localhost',
  user: 'root',       // 替换为你的MySQL用户名
  password: 'password', // 替换为你的MySQL密码
  database: 'auth_system',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0
});

module.exports = pool;

四、创建Express应用

在app.js中设置基础Express应用:

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const authRoutes = require('./routes/auth');

const app = express();

// 中间件
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// 路由
app.use('/api/auth', authRoutes);

// 错误处理
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

五、实现用户模型

在models/user.js中创建用户模型:

const pool = require('../config/db');
const bcrypt = require('bcryptjs');

class User {
  static async findByUsername(username) {
    const [rows] = await pool.query('SELECT * FROM users WHERE username = ?', [username]);
    return rows[0];
  }

  static async findByEmail(email) {
    const [rows] = await pool.query('SELECT * FROM users WHERE email = ?', [email]);
    return rows[0];
  }

  static async create(userData) {
    const { username, email, password } = userData;
    const hashedPassword = await bcrypt.hash(password, 10);
    
    const [result] = await pool.query(
      'INSERT INTO users (username, email, password) VALUES (?, ?, ?)',
      [username, email, hashedPassword]
    );
    
    return { id: result.insertId, username, email };
  }

  static async comparePasswords(plainPassword, hashedPassword) {
    return await bcrypt.compare(plainPassword, hashedPassword);
  }
}

module.exports = User;

六、实现认证控制器

在controllers/auth.js中处理注册和登录逻辑:

const jwt = require('jsonwebtoken');
const User = require('../models/user');

const JWT_SECRET = 'your_jwt_secret_key'; // 生产环境应该使用环境变量

exports.register = async (req, res, next) => {
  try {
    const { username, email, password } = req.body;
    
    // 检查用户名或邮箱是否已存在
    const existingUser = await User.findByUsername(username) || await User.findByEmail(email);
    if (existingUser) {
      return res.status(400).json({ message: 'Username or email already exists' });
    }
    
    // 创建新用户
    const newUser = await User.create({ username, email, password });
    
    res.status(201).json({ 
      message: 'User created successfully', 
      user: newUser 
    });
  } catch (err) {
    next(err);
  }
};

exports.login = async (req, res, next) => {
  try {
    const { username, password } = req.body;
    
    // 查找用户
    const user = await User.findByUsername(username);
    if (!user) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }
    
    // 验证密码
    const isMatch = await User.comparePasswords(password, user.password);
    if (!isMatch) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }
    
    // 生成JWT令牌
    const token = jwt.sign(
      { userId: user.id, username: user.username },
      JWT_SECRET,
      { expiresIn: '1h' }
    );
    
    res.json({ 
      message: 'Login successful', 
      token,
      user: { id: user.id, username: user.username, email: user.email }
    });
  } catch (err) {
    next(err);
  }
};

七、设置路由

在routes/auth.js中定义认证路由:

const express = require('express');
const router = express.Router();
const authController = require('../controllers/auth');

// 注册路由
router.post('/register', authController.register);

// 登录路由
router.post('/login', authController.login);

module.exports = router;

八、测试API

现在你可以使用Postman或其他API测试工具来测试你的服务:

1、注册用户:

POST http://localhost:3000/api/auth/register
Content-Type: application/json

{
  "username": "testuser",
  "email": "test@example.com",
  "password": "password123"
}

2、用户登录:

POST http://localhost:3000/api/auth/login
Content-Type: application/json

{
  "username": "testuser",
  "password": "password123"
}

成功登录后,你将收到一个JWT令牌,可以在后续的请求中使用它来进行身份验证。

九、安全注意事项

在生产环境中,务必将JWT密钥存储在环境变量中

使用HTTPS来保护传输中的数据

考虑实现密码强度要求和账户锁定机制

添加输入验证以防止SQL注入

定期更新依赖库以修复安全漏洞

十、总结

通过本文,我们使用Node.js、Express和MySQL构建了一个完整的用户认证系统。这个系统包含了用户注册、登录和基本的密码加密功能。你可以在此基础上进一步扩展,比如添加密码重置、电子邮件验证、角色权限管理等功能。

这种技术栈组合非常适合中小型Web应用,它提供了良好的性能和开发效率。希望这篇文章能帮助你快速入门Node.js后端开发!

如果你喜欢这篇文章,欢迎关注我的公众号【前端的那点事情】,获取更多精彩内容!