草庐IT

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

lalaxuan 2023-04-08 原文

文章目录

初始化

创建项目

  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,
        })

    })
}

有关Vue3+nodejs全栈项目(资金管理系统)——后端篇(一)登录、注册的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  4. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  5. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  6. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  7. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

    是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

  8. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  9. ruby - (Ruby || Python) 窗口管理器 - 2

    我想用这两种语言中的任何一种(最好是ruby​​)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生

  10. ruby-on-rails - 事件管理员和自定义方法 - 2

    这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什

随机推荐