Vue3+nodejs全栈项目(资金管理系统)——后端篇(一)登录、注册

news2024/11/17 5:23:36

文章目录

  • 初始化
    • 创建项目
    • 配置跨域
    • 配置解析表单数据的中间件
    • 安装bodyparser
    • 初始化用户路由模块
    • 抽离用户路由模块中的处理函数
  • 登录注册
    • 新建admin表
    • 安装并配置mysql模块
    • 注册
      • 检测表单数据是否合法
      • 检测用户名是否被占用
      • 对密码进行加密处理bcryptjs
      • 插入新用户
      • 测试
    • 登录
      • 根据名字查询用户的数据
      • 判断用户输入的密码是否正确
      • 生成 JWT 的 Token 字符串
      • 测试

初始化

创建项目

  1. 新建node-app文件夹作为项目根目录,并在根目录中运行以下命令,初始化包管理配置文件
npm init -y

在这里插入图片描述

  1. 运行以下命令,安装特定版本express
npm i express@4.17.1
  1. 在根目录下新建app.js作为项目入口文件,并初始化以下代码:
// 导入express模块
const express = require('express')

// 导入expressd的服务器实例
const app = express()


// 调用app.listen方法,指定端口号并启动web服务器
app.listen(3000, () => {
    console.log(`api server running at http://127.0.0.1:3000`)
})

配置跨域

  1. 运行以下命令,安装cors中间件:
npm i cors@2.8.5
  1. app.js 中导入并配置 cors 中间件:
// 导入 cors 中间件
const cors = require('cors')
// 将 cors 注册为全局中间件
app.use(cors())

配置解析表单数据的中间件

通过如下的代码,配置解析 application/x-www-form-urlencoded 格式的表单数据的中间件:

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

安装bodyparser

登录、注册要使用post请求 安装body-parser

npm install body-parser

const bodyParser = require("body-parser")
// 使用body-parse中间件 要放在路由之前
//app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

初始化用户路由模块

  1. router 文件夹中,新建 admin.js 文件,作为管理员的路由模块,并初始化代码如下:
const express = require('express')
// 创建路由对象
const router = express.Router()

// 注册
router.post('/register', (req, res) => {
    res.send('register')
})

// 登录
router.post('/login', (req, res) => {
    res.send('login')
})

// 将路由对象共享出去
module.exports = router
  1. app.js 中,导入并使用管理员路由模块:
// 处理管理员(&用户)登录注册相关的路由
const adminRouter = require('./router/admin')
app.use('/api/admin', adminRouter)

抽离用户路由模块中的处理函数

目的:为了保证 路由模块 的纯粹性,所有的 路由处理函数,必须抽离到对应的 路由处理函数模块

  1. /router_handler/admin_handler.js 中,使用 exports 对象,分别向外共享如下两个路由处理函数 :
/**
 * 在这里定义和登录注册相关的路由处理函数
 * 供/router/admin.js模块进行调用
 */

// 注册用户的处理函数
exports.register = (req, res) => {
    res.send('register')
}

// 登录的处理函数
exports.login = (req, res) => {
    res.send('login')
}
  1. /router/admin.js中的代码修改为如下结构:
const express = require('express')
// 创建路由对象
const router = express.Router()

// 导入登录注册处理函数模块
const adminHandler = require('../router_handler/admin_handler')

// 注册
router.post('/register', adminHandler.register)

// 登录
router.post('/login', adminHandler.login)

// 将路由对象共享出去
module.exports = router

登录注册

新建admin表

manage数据库中,新建admin表如下:
在这里插入图片描述

安装并配置mysql模块

在 API 接口项目中,需要安装并配置 mysql 这个第三方模块,来连接和操作 MySQL 数据库

  1. 运行以下命令,安装mysql模块:
npm i mysql@2.18.1
  1. 在根目录下中新建/db/index.js文件,在此自定义模块中创建数据库的连接对象:
// 导入mysql模块
const mysql = require('mysql')

// 创建数据库连接对象
const db = mysql.createPool({
    host: '127.0.0.1',
    user: 'root',
    password: 'IKUN1220',
    database: 'manage'
})

// 向外共享db数据库连接对象
module.exports = db

注册

检测表单数据是否合法

  1. 判断namepassword是否为空
const adminInfo = req.body
if (!adminInfo.name || !adminInfo.password) {
    return res.json({ status: 400, message: '用户名或密码为空' })
}

检测用户名是否被占用

  1. 导入数据库操作模块:
const db = require('../db/index')
  1. 定义sql语句:
const sql = `select * from admin where name = ? `
  1. 执行 SQL 语句并根据结果判断用户名是否被占用:
db.query(sql, [adminInfo.name], (err, results) => {
    // 执行sql语句失败
    if (err) {
        return res.send({
            status: 404,
            message: err.message
        })
    }
		
	// 用户名被占用
    if (results.length > 0) {
        return res.status(400).json('用户名已被注册,请更改后重新注册!')
    }
    // TODO: 用户名可用,继续之后流程
})

对密码进行加密处理bcryptjs

为了保证密码的安全性,不建议在数据库以 明文 的形式保存用户密码,推荐对密码进行 加密存储

在当前项目中,使用 bcryptjs 对用户密码进行加密,优点:

  • 加密之后的密码,无法被逆向破解
  • 同一明文密码多次加密,得到的加密结果各不相同,保证了安全性
  1. 运行如下命令,安装指定版本的 bcryptjs
npm i bcryptjs@2.4.3
  1. /router_handler/admin.js 中,导入 bcryptjs
const bcrypt = require('bcryptjs')
  1. 在注册用户的处理函数中,确认用户名可用之后,调用bcrypt.hashSync(明文密码, 随机盐的长度)方法,对用户的密码进行加密处理:
// 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
adminInfo.password = bcrypt.hashSync(adminInfo.password, 10)

插入新用户

  1. 定义插入用户的sql语句
const sqlStr = 'insert into admin set ?'

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

db.query(sqlStr, { name: adminInfo.name, password: adminInfo.password, identify: adminInfo.identify }, (err, results) => {
   if (err) {
       return res.send({
           status: 400,
           message: err.message
       })
   }

   if (results.affectedRows !== 1) {
       return res.status(400).json('注册用户失败,请稍后再试')
   }

   res.json({
       status: 200,
       message: '注册成功',
       name: adminInfo.name,
       password: adminInfo.password,
       identify: adminInfo.identify
   })
})

})

此时router_handler/amdin_handler.js为:

/**
 * 在这里定义和登录注册相关的路由处理函数
 * 供/router/admin.js模块进行调用
 */
const db = require('../db/index')
const bcrypt = require('bcryptjs')

// 注册用户的处理函数
exports.register = (req, res) => {
    const adminInfo = req.body
    if (!adminInfo.name || !adminInfo.password) {
        return res.json({ status: 400, message: '用户名或密码为空' })
    }

    const sql = `select * from admin where name = ? `
    db.query(sql, [adminInfo.name], (err, results) => {
        if (err) {
            return res.send({
                status: 404,
                message: err.message
            })
        }

        if (results.length > 0) {
            return res.status(400).json('用户名已被注册,请更改后重新注册!')
        }

        // 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
        adminInfo.password = bcrypt.hashSync(adminInfo.password, 10)

        const sqlStr = 'insert into admin set ?'
        db.query(sqlStr, { name: adminInfo.name, password: adminInfo.password, identify: adminInfo.identify }, (err, results) => {
            if (err) {
                return res.send({
                    status: 400,
                    message: err.message
                })
            }

            if (results.affectedRows !== 1) {
                return res.status(400).json('注册用户失败,请稍后再试')
            }

            res.json({
                status: 200,
                message: '注册成功',
                name: adminInfo.name,
                password: adminInfo.password,
                identify: adminInfo.identify
            })
        })

    })
}

// 登录的处理函数
exports.login = (req, res) => {
    res.send('login')
}

测试

在这里插入图片描述在这里插入图片描述

登录

根据名字查询用户的数据

  1. 接收表单数据:
const adminInfo = req.body
  1. 定义sql语句:
const sql = `select * from admin where name = ?`
  1. 执行sql语句,查询用户的数据:
db.query(sql, adminInfo.name, (err, results) => {
    if (err) {
        return res.status(400).json(err)
    }

    if (results.length !== 1) {
        return res.status(400).json('用户不存在')
    }

})

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

核心实现思路:调用 bcrypt.compareSync(用户提交的密码, 数据库中的密码) 方法比较密码是否一致
返回值是布尔值(true 一致、false 不一致)

// 拿着用户输入的密码,和数据库中存储的密码进行对比
const compareResult = bcrypt.compareSync(adminInfo.password, results[0].password)

// 如果对比的结果为false,则证明用户输入的密码错误
if(!compareResult) {
	return res.status(400).json('用户名或密码输入错误,请重新输入')
}

生成 JWT 的 Token 字符串

核心注意点:在生成 Token 字符串的时候,一定要剔除 密码 的值

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

// 剔除完毕之后,admin 中只保留了用户的 id,name, identify 这四个属性的值
const admin = { ...results[0], password: '' }
或者
const admin = {
	id: results[0].id,
	name: results[0].name,
	identify: results[0].identify
}

运行如下的命令,安装生成 Token 字符串的包:

npm i jsonwebtoken@8.5.1

/router_handler/admin_handler.js模块的头部区域,导入jsonwebtoken包:

// 用这个包来生成 Token 字符串
const jwt = require('jsonwebtoken')

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

module.exports = {
  jwtSecretKey: 'zhanglijun',
}

将用户信息对象加密成 Token 字符串(/router_handler/admin_handler.js):

// 导入配置文件
const config = require('../config')

// 生成 Token 字符串
const tokenStr = jwt.sign(admin, config.jwtSecretKey, {
  expiresIn: '10h', // token 有效期为 10 个小时
})

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

res.json({
  status: 200,
  message: '登录成功!',
  // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
  token: 'Bearer ' + tokenStr,
})

测试

在这里插入图片描述在这里插入图片描述在这里插入图片描述
admin_hadler.js代码:

/**
 * 在这里定义和登录注册相关的路由处理函数
 * 供/router/admin.js模块进行调用
 */
const db = require('../db/index')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const config = require('../config')

// 注册用户的处理函数
exports.register = (req, res) => {
    const adminInfo = req.body
    if (!adminInfo.name || !adminInfo.password) {
        return res.json({ status: 400, message: '用户名或密码为空' })
    }

    const sql = `select * from admin where name = ? `
    db.query(sql, [adminInfo.name], (err, results) => {
        if (err) {
            return res.send({
                status: 404,
                message: err.message
            })
        }

        if (results.length > 0) {
            return res.status(400).json('用户名已被注册,请更改后重新注册!')
        }

        // 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
        adminInfo.password = bcrypt.hashSync(adminInfo.password, 10)

        const sqlStr = 'insert into admin set ?'
        db.query(sqlStr, { name: adminInfo.name, password: adminInfo.password, identify: adminInfo.identify }, (err, results) => {
            if (err) {
                return res.send({
                    status: 400,
                    message: err.message
                })
            }

            if (results.affectedRows !== 1) {
                return res.status(400).json('注册用户失败,请稍后再试')
            }

            res.json({
                status: 200,
                message: '注册成功',
                name: adminInfo.name,
                password: adminInfo.password,
                identify: adminInfo.identify
            })
        })

    })
}

// 登录的处理函数
exports.login = (req, res) => {
    const adminInfo = req.body
    const sql = `select * from admin where name = ?`
    db.query(sql, adminInfo.name, (err, results) => {
        if (err) {
            return res.status(400).json(err)
        }

        if (results.length !== 1) {
            return res.status(400).json('用户不存在')
        }

        const compareResult = bcrypt.compareSync(adminInfo.password, results[0].password)
        if (!compareResult) {
            return res.status(400).json('用户名或密码输入错误,请重新输入')
        }

        // const admin = { ...results[0], password: '' }
        const admin = {
            id: results[0].id,
            name: results[0].name,
            identify: results[0].identify
        }
        const tokenStr = jwt.sign(admin, config.jwtSecretKey, {
            expiresIn: '10h', // token 有效期为 10 个小时
        })

        // 将生成的 Token 字符串响应给客户端
        res.json({
            status: 200,
            message: '登录成功!',
            // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
            token: 'Bearer ' + tokenStr,
        })

    })
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31377.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CDH6.3.2处理Zookeeper因未授权访问造成的漏洞

1.zookeeper的基本情况 zookeeper是分布式协同管理工具,常用来管理系统配置信息,提供分布式协同服务。zookeeper官网下载软件包,bin目录下有客户端脚本和服务端脚本。另外还有个工具对理解和使用zookeeper服务非常有用,即zk-ui&am…

文本层次语义元素

html5-文本层次语义元素 第1关_文本层次语义元素相关概念 第2关_文本层次语义元素 编程要求 在右侧编辑器中的Begin - End区域内补充代码&#xff0c;具体要求是&#xff1a; 1.运用HTML5中的语义化元素设计一个文章区(<article>)。 2.文章区中的头部为文章的标题&a…

如何自己开传奇单机架设超详细图文教程

如何自己成为传奇&#xff0c;如何自己搭建传奇非官服&#xff0c;首先下载传奇服务器后&#xff0c;会有两个压缩包&#xff0c;一个用于服务器&#xff0c;一个用于游戏补丁文件 传奇单机设置-GOM引擎的超详细图文教程 版本文件包含.exe&#xff0c;以上文件都不起作用。 …

共享里的文件被删除了怎么办?可尝试这三种恢复方法

共享里的文件被删除了怎么恢复&#xff1f;删除之后就马上去回收站找&#xff0c;可是没回收站里没有怎么办&#xff1f;——来自某xx小伙伴的咨询。如果你也出现同样的疑惑&#xff0c;那么可以尝试下面的三种方法恢复共享里的文件。 方法一、以前的版本恢复 从Windows XP SP…

前端获取ip地址判断国家请求不同baseUrl

项目背景 项目新需求&#xff1a;根据ip地址区分出国内外上网&#xff0c;axios 使用不同的baseurl&#xff0c;上传阿里oss不同bucket 获取ip地址 一、使用js自己获取 使用 RTCPeerConnection.setLocalDescription() WebRTC API pc端没问题&#xff0c;移动端不好使 //获取…

react源码分析:深度理解React.Context

开篇 在 React 中提供了一种「数据管理」机制&#xff1a;React.context&#xff0c;大家可能对它比较陌生&#xff0c;日常开发直接使用它的场景也并不多。 但提起 react-redux 通过 Provider 将 store 中的全局状态在顶层组件向下传递&#xff0c;大家都不陌生&#xff0c;…

第十期|惊!游戏广告主投放十万被骗,推广作弊竟全是虚拟用户

顶象防御云业务情报中心发现&#xff0c;在互联网生态中存在很多灰色的渠道刷量工作室&#xff0c;渠道方通常以低廉的价格通过这些工作室提高广告URL点击量、应用下载激活量、注册量和真实的推广数据提起反馈给广告主结算&#xff0c;但其提供的数据质量和价格一样低廉&#x…

用DevExpress实现基于HTMLCSS的桌面应用程序的UI(一)

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

RabbitMQ的高可用和高可靠

01、什么是高可用机制 所谓高可用&#xff1a;是指产品在规定的条件和规定的时刻或时间内处于可执行规定功能状态的能力。 当业务量增加时&#xff0c;请求也过大&#xff0c;一台消息中间件服务器的会触及硬件&#xff08;CPU,内存&#xff0c;磁盘&#xff09;的极限&#x…

从输入url到页面展现的全过程

作为一道面试经常会问到的题目&#xff0c;看过很多写的很好的博文&#xff0c;整理成自己的笔记 大概来说分为以下几个过程&#xff1a; 输入url地址应用层进行DNS解析应用层生成HTTP请求报文传输层建立TCP连接网络层使用IP协议来选择路线数据链路层实现网络相邻节点间可靠的…

vue-pdf+element实现全屏窗口pdf分页预览,pdf打印实现和解决打印乱码

一.源码 vue-pdf打印实现和乱码解决https://download.csdn.net/download/lucky_fang/85498529 二.全屏窗口打印预览效果 分页预览pdf 窗口采用element窗口模板实现&#xff0c;样式可根据自己喜欢的效果进行修改 Element官方文档 终于可以打印测试了&#xff0c;乱码~&…

【优化求解】粒子群算法求解干扰受限无人机辅助网络优化问题【含Matlab源码 230期】

⛄一、粒子群简介 1 粒子群优化算法 粒子群优化算法( PSO)是指通过模拟鸟群觅食的协作行为,实现群体最优化。PSO是一种并行计算的智能算法,其基本模型如下: 假设群体规模为M,在D维空间中,群体中的第i个个体表示为XD ( xm1,xm2…xm D)T,速度表示为VD ( vm1,vm2…vm D)T,位置( …

聊一聊我对Restful理解

概念 REST原则提倡按照HTTP的语义使用HTTP&#xff0c;如果一个系统符合REST原则&#xff0c;我们就说这个系统是Restful风格的。Restful是Web API设计中非常重要的一个概念&#xff0c;但是很多开发人员对于Restful的理解存在误区。 什么是Restful 在说什么是Restful 之前&…

MES必懂知识,市场需求下的生产管理系统

任何事物的产生和发展都与市场的需求是分不开的&#xff0c;只有当市场需求新生的事物的时候&#xff0c;他才会兴起&#xff0c;有的事物早已经产生&#xff0c;在当时的环境下并未兴起&#xff0c;却在后来才兴盛&#xff0c;这是市场的需求的影响。 MES便是在市场需求下诞生…

高通导航器软件开发包使用指南(9)

高通导航器软件开发包使用指南&#xff08;9&#xff09;8参数说明8.1最小条件参数8.2光学流量数据图8.3光学流量估算数据图8.4光学流量估算图8.5 pos_hold_mode内存8.6体积参数8.7障碍物输出参数8.8速度平滑曲线8参数说明 每辆车必须在适当的位置有运行时参数文件&#xff0c…

How to build several ftp servers on one mac OS

1 How to establish one ftp server locally? I have viewed one article which helps us how to do this on mac OS. You can refer to this link Mac下搭建FTP服务器 please read the tutorial seriously. What I do in the following will be based on it. 2 How to buil…

centos7操作系统开机提示error:file “/boot/grub/i386-pc/normal.mod“ not found

一.问题现象 公司重要业务虚拟机突然业务访问不了&#xff0c;重启操作系统之后发现操作系统启动不了&#xff0c;直接进入救援模式&#xff0c;提示error:file “/boot/grub/i386-pc/normal.mod“ not found&#xff0c;报错截图 二.处理思路 在救援模式下&#xff0c;只有很…

用HTML+CSS做一个简单好看的汽车网页

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

网页开发——淘宝首页导航

这篇博文主要是重新学习&#xff08;复习&#xff09;前端知识&#xff0c;通过写淘宝购物首页导航为案例。 html主要书写内容&#xff1a; 1.首先我写了一个大盒子&#xff0c;用于存放所用的全部标签 <div class"nav">主要内容 </div> 2.插入一张淘宝…

AE/PR模板:镜头光晕炫光动画叠加特效 Premium Overlays Light Leaks

Premium Overlays Light Leaks是一款镜头光晕炫光动画叠加特效的AE/PR模板&#xff0c;非常适用于人物传记、演示文稿、出游vlog、产品展示等场合使用&#xff0c;为您的作品增添更出彩的视觉效果&#xff0c;喜欢的朋友不要错过哦~ 适用软件&#xff1a; AE 2019 或更高, PR 2…