news 2026/8/30 7:28:07

如何通过node.js来实现项目的登录和注册功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何通过node.js来实现项目的登录和注册功能

通过node.js可以实现中小型项目的后端搭建,基于js的语法达到全栈开发的效果。

1.创建项目

在文件夹中自定义命名一个文件,在终端打开,初始化包管理配置文件:

npm init -y

安装新版本的express:

npm i express

在项目根目录下创建app.js文件作为整个项目的入口文件(端口号自定义,避免冲突):

const express = require('express') const app = express() -----中间部分------ app.listen(8082,()=>{ console.log('Express server running at http://127.0.0.1:8082'); })

配置cors跨域,安装cors中间件:

npm i cors

在app.js中导入并配置cors中间件:

const cors = require('cors') app.use(cors())

配置解析表单数据的中间件(解析application/x-www-form-urlencoded格式的表单数据):

app.use(express.urlencoded({extended:false}))

在项目根目录中创建router文件夹,用来存放所有的路由模块;创建router_handler文件夹,用来存放所有的路由处理函数模块

在router文件夹中创建user.js文件,作为用户的路由模块;

const express = require('express') const router = express.Router() router.post('/reguser',(req,res)=>{ res.send('注册成功') }) router.post('/login',(req,res)=>{ res.send('登录成功') }) module.exports = router

然后在app.js文件中导入使用用户路由模块

const userRouter = require('./router/user') app.use('/api',userRouter)

在router_handler文件夹下创建user.js文件,抽离用户路由模块中的处理函数,使用exports对象,向外共享两个处理函数:

exports.reguser = (req,res) => { res.send('注册成功') } exports.login = (req,res) => { res.send('登录成功') }

将/router/user.js中的代码进行修改

const express = require('express') const router = express.Router() // 导入用户路由处理模块 const userHandler = require('../router_handler/user') router.post('/reguser',userHandler.register) //注册 router.post('/login',userHandler.login) //登录 module.exports = router

2.创建数据库(推荐使用Navicat)

定义数据库名称,新建数据表,设计表结构,如图所示:

id为主键,默认为自增,其他字段统一字符集:utf8mb4,排序规则:utf8mb4_0900_ai_ci

在项目终端中安装mysql模块:

npm i mysql2

在根目录创建db/index.js文件,用来创建数据库的连接对象

const mysql = require('mysql2') const db = mysql.createPool({ host:'127.0.0.1', user:'root', password:'123456', database:'my_db_01' }) module.exports = db

3.注册

首先检测表单数据合法性:

// 获取客户端提交到服务的用户信息 const userinfo = req.body // 对表单中的数据进行合法校验 if(!userinfo.username || !userinfo.password){ return res.send({ status:1, message:'用户名或密码不合法!' }) }

检测用户名是否被占用,导入数据库操作模块,定义SQL语句:

// 导入数据库操作模块 const db = require('../db/index') // 定义sql语句,查询用户名是否被占用 const sqlStr = 'select * from ev_users where username=?'

执行SQL语句判断用户名是否被占用:

db.query(sqlStr,userinfo.username,(err,result)=>{ // 执行SQL语句失败 if(err){ return res.send({ status:1, message:err.message }) } // 判断用户名是否被占用 if(result.length > 0){ return res.send({ status:1, message:'用户名已被占用,请重新输入!' }) } })

对密码进行加密处理:安装指定版本的bcryptjs

npm install bcryptjs

在/router_handler/user.js文件中导入bcryptjs

// 导入bcryptjs模块,用于密码加密 const bcrypt = require('bcryptjs')

调用 bcrypt.hashSync()对密码进行加密

userinfo.password = bcrypt.hashSync(userinfo.password,10)

插入新用户,定义插入的SQL语句:

const sql = 'insert into ev_users set ?'

调用db.query()执行SQL语句,插入新用户:

db.query(sql,{username:userinfo.username,password:userinfo.password},(err,result)=>{ // 判断SQL语句是否执行成功 if(err)return res.send({ status:1,message:err.message}) // 判断影响行数是否为1 if(result.affectedRows !== 1)return res.send({ status:1,message:'注册失败!'}) // 注册成功 res.send({ status:0,message:'注册成功!'}) })

对res.send()代码进行优化:

在app.js中,在所有路由之前声明一个全局中间件,为res对象挂载一个res.cc()的函数

app.use((req,res,next)=>{ // status默认值为1,表示失败的情况 // err的值,可能是一个错误对象,也可能是一个字符串 res.cc = (err,status=1)=>{ res.send({ status, message:err instanceof Error ? err.message : err }) } next() })

然后将所有的res.send()代码进行修改:

// 注册用户的处理函数 exports.reguser = (req,res)=>{ // 获取客户端提交到服务的用户信息 const userinfo = req.body // 定义sql语句,查询用户名是否被占用 const sqlStr = 'select * from ev_users where username=?' db.query(sqlStr,userinfo.username,(err,result)=>{ // 执行SQL语句失败 if(err){ return res.cc(err) } // 判断用户名是否被占用 if(result.length > 0){ return res.cc('用户名已被占用,请重新输入!') } // 调用 bcrypt.hashSync()对密码进行加密 userinfo.password = bcrypt.hashSync(userinfo.password,10) // 定义插入新用户的SQL语句 const sql = 'insert into ev_users set ?' db.query(sql,{username:userinfo.username,password:userinfo.password},(err,result)=>{ // 判断SQL语句是否执行成功 if(err)return res.cc(err) // 判断影响行数是否为1 if(result.affectedRows !== 1)return res.cc('注册用户失败!请稍后重试') // 注册成功 res.cc('注册成功!') }) }) }

优化表单数据验证:

安装@hapi/joi包

npm i @hapi/joi

安装@escook/express-joi中间件,实现自动对表单数据进行验证

npm i @escook/express-joi

新建/schema/user.js用户信息验证规则模块

// 导入定义验证规则的包 const joi = require('joi') // 定义用户名和密码的验证规则 const username = joi.string().alphanum().min(1).max(10).required() const password = joi.string().pattern(/^[\S]{6,12}$/).required() // 定义验证注册和登录表单数据的规则对象 exports.reg_login_schema = { body:{ username, password } }

修改router/user.js中的代码

const express = require('express') const router = express.Router() // 导入用户路由处理函数模块 const userHandler = require('../router_handler/user') // 导入验证数据的中间件 const expressJoi = require('@escook/express-joi') // 导入需要的验证规则对象 const {reg_login_schema} = require('../schema/user') // 注册新用户 router.post('/reguser',expressJoi(reg_login_schema),userHandler.reguser) // 登录 router.post('/login',userHandler.login) module.exports = router

在app.js的全局错误级别中间件中,捕获验证失败的错误,并把验证失败的结果响应给客户端

const joi = require('joi') // 定义错误级别的中间件 app.use((err,req,res,next)=>{ // 验证失败导致的错误 if(err instanceof joi.ValidationError) return res.cc(err) // 未知的错误 res.cc(err) })

4.登录

验证登录表单的数据是否合法

修改router/user.js中的登录代码:

/ 登录 router.post('/login',expressJoi(reg_login_schema),userHandler.login)

在router_handler文件中,根据用户名查询用户的数据

// 登录的处理函数 exports.login = (req,res)=>{ // 接收表单数据 const userinfo = req.body // 定义SQL语句 const sql = `select * from ev_users where username=?` // 执行SQL语句,根据用户名查询用户的信息 db.query(sql,userinfo.username,(err,results)=>{ // 执行SQL语句失败 if(err)return res.cc(err) // 执行SQL语句成功但是获取到的数据条数不等于1 if(results.length !== 1)return res.cc('登录失败!') }) }

判断用户输入的密码是否正确

const compareResult = bcrypt.compareSync(userinfo.password,results[0].password) if(!compareResult)return res.cc('登录失败!')

生成JWT的token字符串

通过ES6的高级语法,快速剔除密码和头像的值

const user = { ...results[0] , password:'' , user_pic:''}

安装生成token字符串的包:

npm i jsonwebtoken

在/router_handler/user.js 头部导入jsonwebtoken包

// 导入生成token的包 const jwt = require('jsonwebtoken')

创建config.js 文件,并向外共享加密和还原Token的jwtSecretKey字符串

// 这是一个全局的配置文件 module.exports = { // 这是加密和解密token的密钥 secretKey:'fengrui', // 这是token的过期时间 expiresIn:'10h' }

在router_handler/user.js文件中,将用户信息对象加密成Token字符串

// 导入配置文件 const config = require('../config') // 对用户的信息进行加密,生成token字符串 const tokenStr = jwt.sign(user,config.secretKey,{expiresIn:config.expiresIn})

将生成的token字符串响应给客户端

// 调用res.send()将token响应给客户端 res.send({ status:0, message:'登录成功!', token: 'Bearer ' + tokenStr })

配置解析token的中间件

npm i express-jwt

在app.js中注册路由之前,配置解析token的中间件:

// 一定要在路由之前配置解析token的中间件 const { expressjwt } = require('express-jwt'); const config = require('./config'); // 配置 JWT 解析中间件 app.use( expressjwt({ secret: config.secretKey, algorithms: ['HS256'], }).unless({ path: [/^\/api/] }) // 排除 /api 开头的接口 );

在app.js中的错误级别中间件里面,捕获并处理Token认证失败后的错误

// 定义错误级别的中间件 app.use((err,req,res,next)=>{ // 验证失败导致的错误 if(err instanceof joi.ValidationError) return res.cc(err) // 解析token失败导致的错误 if(err.name === 'UnauthorizedError') return res.cc('身份认证失败!') // 未知的错误 res.cc(err) })

5.Apipost测试

测试注册接口

测试登录接口

测试其他接口

6.相关的安装包版本信息

仅供参考(package.json文件)

{ "name": "api_server", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "type": "commonjs", "dependencies": { "@escook/express-joi": "^1.1.1", "bcryptjs": "^3.0.3", "cors": "^2.8.6", "express": "^4.21.1", "express-jwt": "^8.4.1", "joi": "^17.13.3", "jsonwebtoken": "^9.0.3", "mysql2": "^3.22.2" } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 7:27:49

CVPRW 2026 | 动态场景下多曝光图像融合

题目: NTIRE 2026 The 3rd Restore Any Image Model (RAIM) Challenge: Multi-Exposure Image Fusion in Dynamic Scenes (Track 2) 作者: Lishen Qu; Yao Liu; Jie Liang; Hui Zeng; Wen Dai; Guanyi Qin; Ya-nan Guan; Shihao Zhou; Jufeng Yang; L…

作者头像 李华
网站建设 2026/8/30 7:27:16

MATLAB实现PINN求解二维泊松方程:完整源码与实战指南

简介:本资源是一套基于MATLAB实现的物理信息神经网络(PINN)求解二维泊松方程的完整教学与实践代码,面向计算数学、科学计算及AI for Science方向的本科生、研究生与科研初学者,解决传统数值方法在复杂边界或无网格场景…

作者头像 李华
网站建设 2026/8/30 7:23:36

三极管放大电路详解:直流偏置与静态工作点计算调试

三极管放大是模拟电路里最典型的一道分水岭。很多人能背出 Ic βIb,但一看到实际电路就开始迷糊:为什么基极要接一个电阻到 VCC?为什么不能直接把信号源怼到三极管基极?为什么放大电路一定要用直流电源供电?还有人把“…

作者头像 李华
网站建设 2026/8/30 7:23:32

AMD锐龙7 9800X3D+RX 9070 XT,1.6万游戏主机配置方案

这次我们来看一套 1.6 万元预算的游戏主机配置方案。标题里的“AMD 980X3D”,正确型号是 AMD 锐龙7 9800X3D,它属于 AMD 9000 系列游戏处理器,最核心的优势是 3D V-Cache 缓存技术,对网游和吃 CPU 的游戏帧率提升非常明显&#xf…

作者头像 李华
网站建设 2026/8/30 7:18:30

水中砷超标133倍:从标准解读到Python数据分析实战

1. 背景:从“水中砷超标 133 倍”说起最近看到一条环境污染相关的消息:在 Aughinish 周边水体中,检测出的砷浓度达到了法定限值的 133 倍。很多人看到“133 倍”这个数字,第一反应是震惊,第二反应可能是疑惑&#xff1…

作者头像 李华