在 Web 开发中,用户登录功能是一个基础且重要的部分。、
一、环境搭建
在开始开发之前,我们需要搭建好相应的开发环境。以下是所需的工具和库:
- Node.js:作为 JavaScript 的运行环境,为我们的项目提供支持。
- mysql2:用于与 MySQL 数据库进行交互的驱动程序。
- express:一个流行的 Node.js Web 框架,帮助我们快速搭建 Web 应用。
- ejs:模板引擎,用于生成动态 HTML 页面。
- mysql:关系型数据库,用于存储用户信息。
- mocha:测试工具,可用于对代码进行单元测试。
首先,确保你已经安装了 Node.js 和 MySQL。然后,创建一个新的项目目录,并在该目录下初始化 package.json 文件:
mkdir user-login-project
cd user-login-project
npm init -y
接着,安装所需的依赖:
npm install mysql2 express ejs
npm install --save-dev mocha
二、数据库准备
将 user_db.sql
文件导入到 MySQL 数据库中。你可以使用以下命令:
mysql -u your_username -p your_database_name < user_db.sql
请将 your_username
替换为你的 MySQL 用户名,your_database_name
替换为你要使用的数据库名称。
三、项目结构
为了使项目结构清晰,便于管理和维护,我们采用以下目录结构:
plaintext
user-login-project/
├── public/
│ └── styles.css
├── views/
│ ├── login.ejs
│ └── index.ejs
├── models/
│ └── user.js
├── middleware/
│ └── auth.js
├── app.js
├── package.json
└── test/
└── user.test.js
四、代码实现
4.1 开发登录页面
在 views
目录下创建 login.html
文件,该文件用于显示登录表单。以下是 login.html
的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>Login</h1>
<% if (error) { %>
<p style="color: red;"><%= error %></p>
<% } %>
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required><br>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required><br>
<button type="submit">Login</button>
</form>
</body>
</html>
在 views
目录下创建 index.html
文件,该文件用于显示首页表单。以下是 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>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
<style>
/* 自定义样式 */
body {
font-family: 'Inter', sans-serif;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col">
<header class="bg-blue-600 text-white py-6 px-8 shadow-md">
<h1 class="text-3xl font-bold">欢迎 <%= user.name %> 登录成功!</h1>
</header>
<main class="flex-grow container mx-auto py-12 px-4">
<p class="text-lg text-gray-700 leading-relaxed">这里是首页内容</p>
</main>
<footer class="bg-gray-200 py-6 px-8">
<a href="/logout" class="text-blue-600 hover:text-blue-800 transition duration-300 ease-in-out">
<i class="fa-solid fa-right-from-bracket mr-2"></i>退出登录
</a>
</footer>
</body>
</html>
在这个页面中,我们使用 EJS 模板引擎来动态显示错误信息。如果登录失败,会显示相应的错误提示。
4.2 开发程序入口以及配置
在项目根目录下创建 app.js 文件,这是我们项目的入口文件。以下是 app.js 的代码:
const express = require('express');
const mysql = require('mysql2/promise');
const ejs = require('ejs');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
const port = 3000;
// 配置模板引擎
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// 配置静态文件目录
app.use(express.static(path.join(__dirname, 'public')));
// 解析表单数据
app.use(bodyParser.urlencoded({ extended: true }));
// 创建数据库连接池
const pool = mysql.createPool({
host: 'localhost',
user: 'your_username',
password: 'your_password',
database: 'your_database_name',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// 登录页面
app.get('/login', (req, res) => {
res.render('login', { error: null });
});
// 处理登录请求
app.post('/login', async (req, res) => {
const { username, password } = req.body;
try {
const [rows] = await pool.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);
if (rows.length > 0) {
res.redirect('/');
} else {
res.render('login', { error: 'Invalid username or password' });
}
} catch (error) {
console.error(error);
res.render('login', { error: 'Database error' });
}
});
// 首页
app.get('/', (req, res) => {
res.render('index');
});
// 启动服务器
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
在 app.js 中,我们完成了以下几个重要的配置:
- 配置 EJS 模板引擎,指定视图文件的目录。
- 配置静态文件目录,使浏览器可以访问
public
目录下的静态资源。 - 创建 MySQL 数据库连接池,用于与数据库进行交互。
- 定义了登录页面和处理登录请求的路由。如果登录成功,重定向到首页;如果登录失败,重新渲染登录页面并显示错误信息。
4.3 开发数据模型
在 models
目录下创建 user.js
文件,该文件用于处理与用户相关的数据操作。以下是 user.js
的代码:
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: 'localhost',
user: 'your_username',
password: 'your_password',
database: 'your_database_name',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
const findUserByUsernameAndPassword = async (username, password) => {
try {
const [rows] = await pool.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);
return rows[0];
} catch (error) {
console.error(error);
return null;
}
};
module.exports = {
findUserByUsernameAndPassword
};
在 user.js
中,我们定义了一个 findUserByUsernameAndPassword
函数,用于根据用户名和密码查找用户信息。如果找到匹配的用户,返回该用户的信息;否则返回 null
。
4.4 开发中间件
在 middleware
目录下创建 auth.js
文件,该文件用于验证用户登录信息。以下是 auth.js
的代码:
const { findUserByUsernameAndPassword } = require('../models/user');
const authenticateUser = async (req, res, next) => {
const { username, password } = req.body;
const user = await findUserByUsernameAndPassword(username, password);
if (user) {
req.user = user;
next();
} else {
res.render('login', { error: 'Invalid username or password' });
}
};
module.exports = {
authenticateUser
};
在 auth.js
中,我们定义了一个 authenticateUser
中间件,用于验证用户的登录信息。如果验证成功,将用户信息存储在 req.user
中,并调用 next()
继续处理请求;如果验证失败,重新渲染登录页面并显示错误信息。
五、测试(可选)
为了确保代码的正确性,我们可以使用 Mocha 进行单元测试。在 test
目录下创建 user.test.js
文件,以下是 user.test.js
的代码
const assert = require('assert');
const { findUserByUsernameAndPassword } = require('../models/user');
describe('User Model', () => {
it('should find a user by username and password', async () => {
const user = await findUserByUsernameAndPassword('testuser', 'testpassword');
assert.ok(user);
});
});
在 package.json 中添加测试脚本:
{
"scripts": {
"test": "mocha"
}
}
运行测试:
npm test
六、运行项目
在项目根目录下运行以下命令启动服务器:
node app.js
然后在浏览器中访问 http://localhost:3000/login
即可看到登录页面。
七、总结
通过以上步骤,我们成功地基于 Node.js 开发了一个简单的用户登录功能。在开发过程中,我们使用了 Express 框架搭建 Web 应用,使用 EJS 模板引擎生成动态 HTML 页面,使用 MySQL 数据库存储用户信息,并使用 Mocha 进行单元测试。这个项目可以作为一个基础的示例,帮助你进一步扩展和完善用户登录功能。