一、初始化项目并安装依赖
进入命令行或终端环境,创建一个新的项目目录并初始化Node.js项目:
mkdir auth-app // 创建auth-app文件夹
cd auth-app // 进入auth-app文件夹路径下
npm init -y // 项目初始化
安装必要的依赖包:
npm install
- express:用于创建Web服务器;
- mysql:MySQL数据库的驱动程序;
- bcryptjs:用于密码加密;
- jsonwebtoken:用于生成和验证JWT;
- dotenv:用于管理环境变量。
项目结构如下:
auth-app/
├── db.js
├── app.js
├── public/
│ ├── index.html
│ └── styles.css
└── .env
二、配置环境变量
在项目根目录下创建一个 .env 文件,用于存储敏感信息,如数据库连接信息和JWT密钥:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=yourpassword
DB_NAME=authdb
JWT_SECRET=yoursecretkey
PORT=3000
三、创建数据库连接
在 db.js 文件中创建数据库连接:
const mysql = require('mysql');
const dotenv = require('dotenv');
dotenv.config();const connection = mysql.createConnection({host: process.env.DB_HOST,user: process.env.DB_USER,password: process.env.DB_PASSWORD,database: process.env.DB_NAME
});connection.connect((err) => {if (err) {console.error('Error connecting to MySQL:', err.stack);return;}console.log('Connected to MySQL database');
});module.exports = connection;
四、主应用程序 (app.js)
在 app.js 中创建Express应用,处理注册和登录请求:
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const db = require('./db');
const dotenv = require('dotenv');
const path = require('path');dotenv.config();const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));// 注册接口
app.post('/register', async (req, res) => {const { username, password } = req.body;if (!username || !password) {return res.status(400).json({ message: 'Username and password are required' });}const hashedPassword = await bcrypt.hash(password, 10);const query = 'INSERT INTO users (username, password) VALUES (?, ?)';db.query(query, [username, hashedPassword], (err, result) => {if (err) {return res.status(500).json({ message: 'Error registering user', error: err.message });}res.status(201).json({ message: 'User registered successfully' });});
});// 登录接口
app.post('/login', (req, res) => {const { username, password } = req.body;if (!username || !password) {return res.status(400).json({ message: 'Username and password are required' });}const query = 'SELECT * FROM users WHERE username = ?';db.query(query, [username], async (err, results) => {if (err) {return res.status(500).json({ message: 'Error logging in', error: err.message });}if (results.length === 0) {return res.status(401).json({ message: 'Invalid username or password' });}const user = results[0];const passwordMatch = await bcrypt.compare(password, user.password);if (!passwordMatch) {return res.status(401).json({ message: 'Invalid username or password' });}const token = jwt.sign({ id: user.id, username: user.username }, process.env.JWT_SECRET, { expiresIn: '1h' });res.status(200).json({ message: 'Login successful', token });});
});const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {console.log(`Server is running on port ${PORT}`);
});
五、HTML文件(public/index.html)
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>用户注册和登录</title><link rel="stylesheet" href="styles.css">
</head>
<body><h1>用户注册</h1><form id="registerForm"><input type="text" name="username" placeholder="用户名" required><input type="password" name="password" placeholder="密码" required><button type="submit">注册</button></form><h1>用户登录</h1><form id="loginForm"><input type="text" name="username" placeholder="用户名" required><input type="password" name="password" placeholder="密码" required><button type="submit">登录</button></form><div id="message"></div><script>document.getElementById('registerForm').addEventListener('submit', async (event) => {event.preventDefault();const formData = new FormData(event.target);const data = Object.fromEntries(formData);try {const response = await fetch('/register', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(data)});const result = await response.json();document.getElementById('message').innerText = result.message;} catch (error) {document.getElementById('message').innerText = '注册失败: ' + error.message;}});document.getElementById('loginForm').addEventListener('submit', async (event) => {event.preventDefault();const formData = new FormData(event.target);const data = Object.fromEntries(formData);try {const response = await fetch('/login', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(data)});const result = await response.json();document.getElementById('message').innerText = result.message;if (response.ok && result.token) {localStorage.setItem('token', result.token);}} catch (error) {document.getElementById('message').innerText = '登录失败: ' + error.message;}});</script>
</body>
</html>
六、CSS样式 (public/styles.css)
body {font-family: Arial, sans-serif;background-color: #f4f4f4;padding: 20px;
}h1 {margin-top: 0;
}form {margin: 10px 0;padding: 10px;background: white;border: 1px solid #ddd;border-radius: 5px;
}input {width: 100%;padding: 10px;margin: 5px 0 10px;border: 1px solid #ddd;border-radius: 5px;box-sizing: border-box;
}button {padding: 10px;background: #5cb85c;color: white;border: none;border-radius: 5px;cursor: pointer;
}button:hover {background: #4cae4c;
}#message {margin-top: 20px;font-weight: bold;
}
七、创建数据库和用户表
确保你的数据库设置正确并创建所需的表。你可以使用以下SQL命令:
CREATE DATABASE authdb; // 创建authdb数据库USE authdb; // 使用authdb数据库// 创建users表
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(255) NOT NULL UNIQUE,password VARCHAR(255) NOT NULL
);
注意:不要漏掉分号!!!
八、运行应用
node app.js
打开浏览器,访问 http://localhost:3000
九、如果你没安装MySQL的话看这里
安装地址:mysql官网
具体安装步骤看这里:mysql安装步骤
建议:强烈建议安装最新版MySQL!!!
mysql报错1
如果连接mysql报错如下:
解决办法: 可以通过升级mysql版本或修改配置解决。
原因: 最新的mysql模块并未完全支持MySQL 8的 caching_sha2_password 加密方式,而 caching_sha2_password 在MySQL 8中是默认的加密方式。默认已经使用了 caching_sha2_password 加密方式,该账号、密码无法在mysql模块中使用。
具体修改加密方式的方法:
1、use mysql;
2、alter user ‘root’@‘localhost’ identified with mysql_native_password by ‘你的数据库密码’;
3、flush privileges;
注:如果失败,请查看是否是以管理员的身份打开。
报错2
这个报错的原因是监听的接口已被占用,解决的方法是打开计算机管理,然后重新启动mysql。