Node.js + MySQL 实现用户注册与登录功能
在Node.js后端开发中,实现用户注册与登录是构建Web应用的基础环节。本文将展示如何利用原生http模块、mysql驱动及crypto模块,搭建一个支持用户名校验、密码加密存储及查询比对的简易注册登录系统。
核心依赖与安全基础
实现该功能需要引入几个关键的Node.js内置模块及第三方库。数据库操作依赖mysql包建立连接池,密码处理则使用内置的crypto模块进行哈希运算。为了确保安全性,存储在数据库中的密码绝不应是明文,而应经过不可逆的哈希处理。
首先,定义密码加密函数。这里采用两次MD5哈希(双MD5)来增加破解难度,并调用crypto.createHash生成十六进制摘要:
// 密码加密工具函数
function md5(str) {
let obj = crypto.createHash('md5');
obj.update(str);
return obj.digest('hex');
}
// 二次哈希增强安全性
function md5_2(str) {
return md5(md5(str));
}
数据库连接配置
在生产环境中,建议始终使用连接池而非单一连接,以提高并发处理能力并自动管理断连重连。以下代码展示了如何初始化MySQL连接池:
// 创建数据库连接池
let db = mysql.createPool({
host: 'localhost',
user: 'your_user',
password: 'your_password',
database: 'your_database'
});
// 通用查询方法
// db.query(`sql语句`, (err, data) => {})
服务端路由与业务逻辑实现
整个逻辑围绕HTTP服务器的请求解析展开。利用url.parse获取路径和查询参数,根据路径区分注册(/reg)、登录(/login)及其他静态资源访问。
第1步:处理用户注册 (/reg)
注册逻辑包含多层校验:检查字段是否为空、验证用户名格式、检查密码非法字符,并最终确认用户名唯一性。只有所有校验通过,才执行插入操作。
- 入口:GET/POST
/reg?user=xxx&password=xxx - 动作:
- 解析URL参数获取
user和password。 - 校验
user不能为空,且符合正则/\w{4,16}$/(4-16位字母数字下划线)。 - 校验
password不能为空,且不含引号以防止注入干扰。 - 查询
users_table表,确认该username不存在。 - 若存在,返回错误;若不存在,将密码经
md5_2加密后INSERT入库。
- 解析URL参数获取
- 完成状态:返回JSON
{"err":0,"msg":"注册成功"}或具体错误信息。
case '/reg':
if(!user) {
res.write('{"err":1,"msg":"用户名不能为空"}');
res.end(); break;
} else if(!password) {
res.write('{"err":1,"msg":"密码不能为空"}');
res.end(); break;
} else if(/\w{4,16}$/.test(user)) { // 注意:原代码此处逻辑似有误,通常应为 !test 或 /匹配失败才报错
// 假设原意是校验不符合格式时返回错误,需根据实际正则需求调整
res.write('{"err":1,"msg":"用户名格式错误"}');
res.end(); break;
} else if(/["|']/.test(password)) {
res.write('{"err":1,"msg":"密码非法"}');
res.end(); break;
} else {
// 检查用户是否存在
db.query(`SELECT username FROM users_table WHERE username='${user}'`,(err,data)=>{
if(err){
res.write('{"err":1,"msg":"数据库错误"}');
console.log(err); res.end();
}else{
if(data.length > 0){
res.write('{"err":1,"msg":"用户名已存在"}');
}else{
res.write('{"err":0,"msg":"注册成功"}');
// 插入新用户,密码已加密
db.query(`INSERT INTO users_table (ID,username,password) VALUES (0,'${user}','${md5_2(password)}')`);
}
res.end();
}
});
}
break;
第2步:处理用户登录 (/login)
登录流程类似,主要区别在于验证成功后不需写入数据库,而是比对密码哈希值。
- 入口:GET/POST
/login?user=xxx&password=xxx - 动作:
- 校验参数非空及格式。
- 从
users_table中查询指定username的记录。 - 若记录不存在,提示“用户不存在”。
- 若存在,比较输入的密码经
md5_2处理后的结果与数据库中存储的password字段是否一致。
- 完成状态:密码匹配返回
{"err":0,"msg":"登陆成功"},否则提示“用户名或密码不正确”。
case '/login':
// ... 前置校验代码同注册 ...
if(/* 校验通过 */){
db.query(`SELECT username,password FROM users_table WHERE username='${user}'`,(err,data)=>{
if(err){
res.write('{"err":1,"msg":"数据库错误"}');
res.end();
} else if(data.length > 0){
if(md5_2(password) != data[0].password){
res.write('{"err":1,"msg":"用户名或密码不正确"}');
} else {
res.write('{"err":0,"msg":"登陆成功"}');
}
} else {
res.write('{"err":1,"msg":"用户不存在"}');
}
res.end();
});
}
break;
第3步:静态文件服务与默认路由
对于非注册登录的请求,服务器尝试读取当前目录下的静态文件。如果文件存在,则通过gzip压缩后返回;如果文件缺失,则返回404状态码。
default:
let rs = fs.createReadStream(`www${pathname}`);
let gz = zlib.createGzip();
res.setHeader('content-encoding','gzip');
rs.pipe(gz).pipe(res);
rs.on('error', err=>{
res.writeHead(404);
res.write('Not Found');
res.end();
});
break;
注意事项与优化建议
上述代码提供了一个功能完备的最小化示例,但在实际生产环境中,还需关注以下几点:
- SQL注入风险:原文代码直接使用模板字符串拼接SQL(如
WHERE username='${user}')。虽然前端做了简单的字符过滤,但这不足以防御SQL注入。强烈建议使用mysql提供的占位符机制(如db.query('SELECT * FROM users_table WHERE username=?', [user], callback))。 - 协议选择:示例中通过URL Query参数传递密码,这在HTTPS普及的今天极不安全。现代应用应使用POST请求的Body传递数据,并配合HTTPS传输。
- 密码算法:MD5已被证实存在碰撞漏洞,不再推荐用于高安全场景。建议改用
bcrypt或argon2等专门设计的慢速哈希算法。 - 错误处理:当前的错误处理较为简单,仅向客户端输出JSON字符串,缺乏统一的异常捕获中间件机制。
以上就是基于Node.js和MySQL实现注册登录功能的详细内容,更多关于Node.js后端开发实践的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









