在mySQL中创建users表
安装配置mysql模块2.18.1版本
注册
实现步骤
1、检测表单数据是否合法
2、检测用户名是否被占用
3、对密码进行加密处理
4、插入新用户
检测表单数据是否合法
1、判断用户名和密码是否为空
//获取客户端提交到服务器的用户信息
const userinfo = req.body
//对表单中的数据,进行合法性的检验
if(!userinfo.username || !userinfo.password){
return res.send({
status:1,
message:'用户名或密码不合法',
})
}
检测用户名是否被占用
1、导入数据库模块
2、定义sql语句
//定义SQL语句查询用户名是否被占用
const sqlStr = 'select * from users where username=?'
//select语句results返回的是数组,因此判断时只需要看数组长度是否大于0
db.query(sqlStr,userinfo.username,(err,results)=>{
if(err){
return res.send({
status:1,
message:err.message,
})
}
//判断用户名是否被占用
if(results.length >0){
return res.send({
status:1,
message:'用户名被占用,请更换其他用户名'
})
}
//TODO:用户名可以使用
})
对密码进行加密
使用bcryptjs包进行加密,优点:
- 加密之后的密码,无法被逆向破解
- 同一明文密码多次加密,得到的加密结果各不相同
安装 bcryptjs包,2.4.3版本
调用 bcrypt.hashSync(明文密码,随机的长度)方法,对密码进行加密处理
//调用bcrypt.hashSync 对密码进行加密
userinfo.password=bcrypt.hashSync(userinfo.password,10)
插入新用户
//定义插入新用户的sql语句
const sql = 'insert into users set ?'
db.query(sql,{username:userinfo.username,password:userinfo.password},(err,results)=>{
if(err){
return res.send({
status:1,
message:err.message,
})
}
//判断影响行数是否为1
if(results.affectedRows !==1){
return res.send({
status:1,
message:'注册用户失败,请稍后再试'
})
}
//注册用户成功
res.send({
status:0,
message:'注册成功!'
})
})
优化代码
1、对res.send()进行优化
//在路由之前,封装res.cc函数
app.use((req,res,next)=>{
//status 默认值为1,表示失败的情况
//err都值,可能是一个错误对象,也可能是一个错误的描述字符串
res.cc = function (err,status = 1) {
res.send({
status,
message:err instanceof Error ? err.message : err
})
}
next()
})
// return res.send({
// status:1,
// message:err.message,
// })
//修改后
return res.cc(err)
2、优化表单数据验证
使用第三方数据验证模块,来降低出错率、提高验证的效率与可维护性
- 安装 hapi/joi 包,为表单中携带的每个数据项,定义验证规则:
npm install @hapi/joi@17.1.0
- 安装 escook/express-joi 用来实现自动对表单数据进行验证的功能:
npm install escook/express-joi
创建文件
写入规则
//定义 用户信息验证规则模块
const joi = require('@hapi/joi')
/**
* string() 值必须是字符串
* alphanum() 值只能包含字母和数字的字符串
* min(length) 最小长度
* max(length) 最大长度
* required() 的值是必须项,不能为undefined
* pattern(正则表达式) 值必须符合正则表达式的规则
* **/
//用户名验证规则
const username = joi.string().alphanum().min(1).max(10).required()
//密码的验证规则
const password = joi.string().pattern(/^[\S]{6,12}]$/).required()
//注册和登录表单的验证规则对象
exports.reg_login_schema = {
//表示需要对req.body 中的数据进行验证
body :{
username,
password,
},
}
修改/router/user.js 中的代码
const userHandler = require('../router_handler/user')
//导入验证表单数据的中间件
const expressJoi = require('@escook/express-joi')
//导入验证表单数据的验证规则对象
const { reg_login_schema } = require('../schema/user')
//注册新用户
// router.post('/reguser',userHandler.regUser)
//修改后
router.post('/reguser',expressJoi(reg_login_schema),userHandler.regUser)
//登录
// router.post('/login',userHandler.login)
router.post('/login',userHandler.login)
在app.js 的全局错误界别中间件中,捕获验证失败的错误,并把验证失败的结果响应给客户端:
const joi = require('@hapi/joi')
//定义错误级别的中间件
app.use(function (err,req,res,next){
//数据验证失败导致的错误
if(err instanceof joi.ValidationError) return res.cc(err)
//未知错误
res.cc(err)
})
登录
实现步骤
- 检测表单数据是否合法
- 根据用户名查询用户的数据
- 判断用户输入的密码是否争取
- 生成JWT的Token字符串
检测登录表单的数据是否合法
将 /router/user.js 中登录的路由代码修改
//登录
// router.post('/login',userHandler.login)
router.post('/login',expressJoi(reg_login_schema),userHandler.login)
根据用户名查询用户的数据
- 接收表单数据
const userinfo = req.body
- 定义SQL语句
const sql = 'select * from users where username=?'
- 执行SQL语句
//接收表单数据
const userinfo = req.body
//定义SQL语句
const sql = 'select * from 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('登录失败!')
})
判断用户输入的面是否正确
核心思路:调用bcrypt.compareSync(用户提交的棉麻,数据库中的密码) 方法比较密码是否一直
返回值(true 表示一致,false 表示不一致)
//使用用户输入的密码,和数据库中存储的棉麻进行比较
const compareResult = bcrypt.compareSync(userinfo.password,results[0].password)
//如果对比的结果等于false,密码错误
if(!compareResult){
return res.cc('登录失败')
}
生成JWT的Token字符串
通过ES6的高级语法,快速剔除 密码 和 头像 的值
const user = {...results[0],password:'',user_pic:''}
安装Token字符串包
npm i jsonwebtoken@8.5.1
在handler/user.js中修改
//导入生成Token 的包
const jwt=require('jsonwebtoken')
//导入全局的配置文件
const config = require('../config')
//在服务器端生成Token字符串
//通过ES6语法快速剔除 密码 头像 敏感信息
const user = {...results[0],password:'',user_pic:''}
//对用户的信息进行加密,生成Token字符串
const tokenStr = jwt.sign(user,config.jwtSecretKey,{expiresIn:config.expiresIn})
//调用res.send()将Token响应给客户端
res.send({
status:0,
message:'登录成功!',
token:'Bearer '+tokenStr
})
创建config.js制定全局配置
//这是一个全局的配置文件
module.exports={
//加密和解密Token的密钥
jwtSecretKey:'lanlan ^v^',
expiresIn:'10h'
}
配置解析Token 的中间件
安装包
npm install express-jwt@5.3.3
在app.js 中注册路由之前,配置解析Token的中间件
//导入配置文件
const config = require('./config')
//解析token的中间件
const expressJWT = require('express-jwt')
//使用 .unless({path:[/^\/api\//]})指定哪些接口不需要进行Token 的身份认证
app.use(expressJWT({secret:config.jwtSecretKey}).unless({path:[/^\/api\//]}))
在app.js中的错误级别中间件中,捕获并处理Token认证失败后的错误
- 本文链接:https://archer-lan.github.io/2022/03/04/Node.js%20%E5%AD%A6%E4%B9%A0-%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。